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 exampleResultSet.one()with zero or several rows, an unknownset_wal_flush()mode, orAsyncExecutor.set_commit_every()with a count below 1AttributeError:set()on an immutable record, such as one returned by a query; call.modify()firstTimeoutError:AsyncExecutor.wait_completion(timeout_ms)when the timeout expires (at once fortimeout_ms=0while work is pending)TypeError: a value that JPype cannot convert, for example adatetime.timepassed toset()- Java exceptions, not wrapped:
Schemacalls that go directly to Java, such asexists_type(),get_types(),get_indexes(), andexists_index(); a wrapper'ssave()outside a transaction (com.arcadedb.exception.TransactionException: Transaction not begun;db.new_vertex()anddb.new_document()themselves work outside one); and a vector of the wrong dimension saved to an indexed property (java.lang.IllegalArgumentException, raised bysave())
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¶
Print Full Exception Details¶
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¶
- Database API - Database operations that may raise errors
- Transactions API - Transaction error handling
- Server API - Server-related errors
- Troubleshooting Guide - Common issues and solutions