Skip to content

Exceptions API

The ArcadeDBError exception is the base class for all errors raised by the ArcadeDB Python bindings. It wraps underlying Java exceptions and provides Pythonic error handling.

Overview

Most errors from ArcadeDB operations raise ArcadeDBError (there are no subclasses yet). From 26.10.1, when it is raised from a Java exception, its str() ends with (caused by <Java class>: <message>) naming the Java root cause, unless that message is already in the text. Earlier wheels often showed only the engine's generic outer message. The engine computes rows lazily, so a statement's error can come while its result set is read rather than from query(); from 26.10.1 every way of reading a result set raises it as ArcadeDBError too, where earlier wheels let the Java exception through. Some calls raise other exceptions:

  • ValueError: invalid arguments, for example ResultSet.one() with zero or several rows, an unknown set_wal_flush() mode, or AsyncExecutor.set_commit_every() with a count below 1
  • AttributeError: set() on an immutable record, such as one returned by a query; call .modify() first
  • TimeoutError: AsyncExecutor.wait_completion(timeout_ms) when the timeout expires (at once for timeout_ms=0 while work is pending)
  • TypeError: a value that JPype cannot convert, for example a datetime.time passed to set()
  • Java exceptions, not wrapped: Schema calls that go directly to Java, such as exists_type(), get_types(), get_indexes(), and exists_index(); a wrapper's save() outside a transaction (com.arcadedb.exception.TransactionException: Transaction not begun; db.new_vertex() and db.new_document() themselves work outside one); and a vector of the wrong dimension saved to an indexed property (java.lang.IllegalArgumentException, raised by save())

Error Sources:

  • Schema violations: Type mismatches, constraint failures, missing properties
  • Transaction errors: Concurrent modifications, commit failures, rollbacks
  • Query errors: Syntax errors, invalid queries, type errors
  • Database errors: File I/O errors, corruption, not found
  • Server errors: Connection failures, authentication errors, port conflicts
  • Resource errors: Out of memory, too many open files

ArcadeDBError Class

class ArcadeDBError(Exception):
    """Base exception for ArcadeDB errors."""

    def __str__(self):
        # The message, followed by "(caused by <Java class>: <message>)" naming
        # the Java root cause when that message is not already in the text
        ...

Inheritance: Exception → ArcadeDBError

Usage:

CRUD style in this page

Prefer SQL/OpenCypher for normal application writes. Where this page still shows wrapper objects, it is to discuss exception behavior around record-level APIs or to keep examples close to the API being documented.

from arcadedb_embedded import ArcadeDBError

try:
    # ArcadeDB operation
    db.query("sql", "INVALID SYNTAX")
except ArcadeDBError as e:
    print(f"Database error: {e}")

Common Error Patterns

Database Not Found

from arcadedb_embedded import ArcadeDBError, open_database

try:
    db = open_database("./nonexistent_db")
except ArcadeDBError as e:
    print(f"Error: {e}")
    # Error: Failed to open database: com.arcadedb.exception.DatabaseNotFoundException:
    # Database '/abs/path/to/nonexistent_db' does not exist

Solution: Use database_exists() to check first, or use create_database().


Query Syntax Error

try:
    result = db.query("sql", "SELCT FROM Person")  # Typo: SELCT
except ArcadeDBError as e:
    print(f"Query error: {e}")
    # Query error: ... syntax error near 'SELCT'

Solution: Check query syntax, use proper SQL/OpenCypher.


Schema Constraint Violation

# Assuming User.email has UNIQUE constraint
try:
    with db.transaction():
        db.command("sql", "INSERT INTO User SET email = ?", "alice@example.com")
        db.command("sql", "INSERT INTO User SET email = ?", "alice@example.com")

except ArcadeDBError as e:
    print(f"Constraint violation: {e}")
    # Constraint violation: ... duplicate key ... email

Solution: Check for existing records before insert, handle duplicates gracefully.


Type Mismatch

# Assuming Person.age is INTEGER
try:
    with db.transaction():
        db.command("sql", "INSERT INTO Person SET age = ?", "not a number")

except ArcadeDBError as e:
    print(f"Type error: {e}")
    # Type error: ... cannot convert 'not a number' to INTEGER

Solution: Ensure data types match schema definitions.


Transaction Error

try:
    # Commit without a transaction (not allowed)
    db.commit()  # Error: Transaction not begun

except ArcadeDBError as e:
    print(f"Transaction error: {e}")

Solution: Use context managers (with db.transaction()) to avoid manual transaction management errors.


Property Not Found

Reading a property that does not exist is not an error: get() returns None.

person = db.query("sql", "SELECT FROM Person LIMIT 1").first()

# A missing property (or a typo in its name) returns None; nothing is raised
phone = person.get("phone_number")
if phone is None:
    print("phone_number is not set")

Solution: Use has_property() when you need to tell a missing property from one stored as null.


Server Already Running

from arcadedb_embedded import create_server, ArcadeDBError

server = create_server(root_password="password123")
server.start()

try:
    server.start()  # Already started!
except ArcadeDBError as e:
    print(f"Server error: {e}")
    # Server error: Server is already started
finally:
    server.stop()

Solution: Check server.is_started() before calling start().


Port Already in Use

try:
    server = create_server(root_password="password123", config={"http_port": 2480})
    server.start()
except ArcadeDBError as e:
    if "bind" in str(e).lower() or "port" in str(e).lower():
        print("Port 2480 is already in use")
        print("Try a different port or stop conflicting process")
    else:
        print(f"Server error: {e}")

Solution: Use a different port or stop the process using port 2480.


Error Handling Best Practices

Specific Error Handling

from arcadedb_embedded import ArcadeDBError

try:
    db = open_database("./mydb")
    result = db.query("sql", "SELECT FROM Person WHERE age > 25")

except ArcadeDBError as e:
    error_msg = str(e).lower()

    if "does not exist" in error_msg:
        print("Database not found - creating new one")
        db = create_database("./mydb")

    elif "syntax" in error_msg:
        print("Query syntax error - check your SQL")

    elif "constraint" in error_msg:
        print("Constraint violation - check your data")

    else:
        print(f"Unknown error: {e}")
        raise

Transaction Error Handling

db.run_in_transaction(fn, retries=12, backoff_s=0.005) runs fn in a transaction, rolls back on any error, and retries on ConcurrentModificationException and NeedRetryException with a linear backoff. Any other error, or a conflict after the last retry, is raised.

from arcadedb_embedded import ArcadeDBError

def safe_insert(db, record_data):
    """Insert with automatic retry on concurrent modification."""
    assignments = ", ".join(f"{key} = ?" for key in record_data)

    def write():
        db.command(
            "sql",
            f"INSERT INTO Record SET {assignments}",
            *record_data.values(),
        )

    db.run_in_transaction(write)

# Usage
try:
    safe_insert(db, {"name": "Alice", "age": 30})
    print("Insert successful")
except ArcadeDBError as e:
    print(f"Insert failed: {e}")

Graceful Degradation

from arcadedb_embedded import ArcadeDBError

def get_user_safely(db, email):
    """Get user with fallback on error."""
    try:
        result = db.query("sql", "SELECT FROM User WHERE email = ?", email)
        return result.first()  # Result or None if no rows

    except ArcadeDBError as e:
        print(f"Warning: Database query failed: {e}")
        # Return None or default value instead of crashing
        return None

# Usage
user = get_user_safely(db, "alice@example.com")
if user:
    print(f"Found user: {user.get('name')}")
else:
    print("User not found or error occurred")

Cleanup on Error

from arcadedb_embedded import ArcadeDBError, create_server

server = None
db = None

try:
    # Start server
    server = create_server(root_password="password123")
    server.start()

    # Create database
    db = server.create_database("temp_db")

    # Do work
    with db.transaction():
        db.command("sql", "INSERT INTO Test SET data = ?", "value")

except ArcadeDBError as e:
    print(f"Error: {e}")

finally:
    # Always cleanup
    if db:
        db.close()
    if server and server.is_started():
        server.stop()
    print("Cleanup complete")

Logging Errors

import logging
from arcadedb_embedded import ArcadeDBError

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

try:
    # A read needs no transaction, and a scan runs in parallel only outside one
    result = db.query("sql", "SELECT FROM LargeTable")
    for record in result:
        process(record)

except ArcadeDBError as e:
    logger.error(f"Database operation failed: {e}", exc_info=True)
    # Log includes full stack trace
    raise

Complete Error Handling Example

import arcadedb_embedded as arcadedb
from arcadedb_embedded import ArcadeDBError
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def safe_database_operation():
    """Comprehensive error handling example."""
    db = None

    try:
        # Check if database exists
        if not arcadedb.database_exists("./mydb"):
            logger.info("Database not found - creating")
            db = arcadedb.create_database("./mydb")

            # Initialize schema
            db.command("sql", "CREATE DOCUMENT TYPE Person")
            db.command("sql", "CREATE PROPERTY Person.name STRING")
            db.command("sql", "CREATE PROPERTY Person.email STRING")
            db.command("sql", "CREATE INDEX ON Person (email) UNIQUE_HASH")
        else:
            db = arcadedb.open_database("./mydb")

        # Insert records with error handling
        people = [
            {"name": "Alice", "email": "alice@example.com"},
            {"name": "Bob", "email": "bob@example.com"},
            {"name": "Charlie", "email": "alice@example.com"},  # Duplicate!
        ]

        success_count = 0
        error_count = 0

        for person in people:
            try:
                with db.transaction():
                    db.command(
                        "sql",
                        "INSERT INTO Person SET name = ?, email = ?",
                        person["name"],
                        person["email"],
                    )

                success_count += 1
                logger.info(f"Inserted: {person['name']}")

            except ArcadeDBError as e:
                error_count += 1
                error_msg = str(e).lower()

                if "duplicate" in error_msg or "unique" in error_msg:
                    logger.warning(f"Skipped duplicate: {person['email']}")
                else:
                    logger.error(f"Failed to insert {person['name']}: {e}")

        logger.info(f"Completed: {success_count} success, {error_count} errors")

        # Query with error handling
        try:
            result = db.query("sql", "SELECT * FROM Person")
            count = len(list(result))
            logger.info(f"Total people in database: {count}")
        except ArcadeDBError as e:
            logger.error(f"Query failed: {e}")

        return True

    except ArcadeDBError as e:
        logger.error(f"Database operation failed: {e}", exc_info=True)
        return False

    finally:
        if db:
            try:
                db.close()
                logger.info("Database closed successfully")
            except ArcadeDBError as e:
                logger.error(f"Error closing database: {e}")

# Run
if __name__ == "__main__":
    success = safe_database_operation()
    if success:
        print("Operation completed successfully")
    else:
        print("Operation failed - check logs")

Debugging Tips

import traceback
from arcadedb_embedded import ArcadeDBError

try:
    db.query("sql", "INVALID QUERY")
except ArcadeDBError as e:
    print("Error occurred:")
    print(f"  Message: {e}")
    print(f"  Type: {type(e).__name__}")
    print("\nFull traceback:")
    traceback.print_exc()

Check Java Exception

from arcadedb_embedded import ArcadeDBError

try:
    # Operation that might fail
    db.query("sql", "SELECT FROM NonExistentType")
except ArcadeDBError as e:
    print(f"Python error: {e}")

    # The __cause__ attribute contains the original Java exception
    if e.__cause__:
        print(f"Java cause: {e.__cause__}")
        print(f"Java type: {type(e.__cause__).__name__}")

Validate Before Operations

def validate_schema(db, type_name, properties):
    """Return True if the type and every listed property exist."""
    if not db.schema.exists_type(type_name):
        return False
    doc_type = db.schema.get_type(type_name)
    return all(doc_type.existsProperty(prop) for prop in properties)

# Usage
if validate_schema(db, "Person", ["name", "email"]):
    # Safe to proceed
    with db.transaction():
        db.command(
            "sql",
            "INSERT INTO Person SET name = ?, email = ?",
            "Alice",
            "alice@example.com",
        )

Error Categories

Schema Errors

  • Type doesn't exist
  • Property doesn't exist
  • Type mismatch (e.g., string → integer)
  • Constraint violation (unique, mandatory, etc.)

Prevention:

  • Define schema upfront with CREATE TYPE
  • Use schema validation before operations
  • Handle type conversion explicitly

Transaction Errors

  • No active transaction
  • Concurrent modification
  • Commit failure
  • Rollback failure

Prevention:

  • Use context managers (with db.transaction())
  • Keep transactions short
  • Use db.run_in_transaction(fn) to retry on concurrent modifications

Query Errors

  • Syntax errors
  • Invalid language
  • Type not found
  • Invalid property reference
  • Invalid function usage

Prevention:

  • Validate queries with test data first
  • Use parameterized queries when possible
  • Test query syntax in Studio UI

Resource Errors

  • Database not found
  • Database already exists
  • Cannot create database
  • File I/O errors
  • Out of memory

Prevention:

  • Check database_exists() before operations
  • Ensure sufficient disk space
  • Use appropriate batch sizes for imports

Server Errors

  • Server already running
  • Port in use
  • Cannot bind to address
  • Database not accessible

Prevention:

  • Check is_started() before operations
  • Use available ports
  • Ensure proper permissions

See Also