lfnovo/open-notebook · critical · DatabaseOperationError
Error fetching all {cls.table_name}: {str(e)}
Error message
Error fetching all {cls.table_name}: {str(e)} What it means
get_all() wraps its database query in a broad try/except: any exception from repo_query, row deserialization (target_class(**row)), or the SurrealDB connection is logged and re-raised as DatabaseOperationError. It signals an infrastructure/deserialization failure, not bad input.
Source
Thrown at open_notebook/domain/base.py:102
if order_by:
validated_order_by = cls._validate_order_by(order_by)
query = f"SELECT * FROM {table_name} ORDER BY {validated_order_by}"
else:
query = f"SELECT * FROM {table_name}"
result = await repo_query(query)
objects = []
for obj in result:
try:
objects.append(target_class(**obj))
except Exception as e:
logger.critical(f"Error creating object: {str(e)}")
return objects
except Exception as e:
logger.error(f"Error fetching all {cls.table_name}: {str(e)}")
logger.exception(e)
raise DatabaseOperationError(e)
@classmethod
async def get(cls: Type[T], id: str) -> T:
if not id:
raise InvalidInputError("ID cannot be empty")
try:
# Get the table name from the ID (everything before the first colon)
table_name = id.split(":")[0] if ":" in id else id
# If we're calling from a specific subclass and IDs match, use that class
if cls.table_name and cls.table_name == table_name:
target_class: Type[T] = cls
else:
# Otherwise, find the appropriate subclass based on table_name
found_class = cls._get_class_by_table_name(table_name)
if not found_class:
raise InvalidInputError(f"No class found for table {table_name}")
target_class = cast(Type[T], found_class)View on GitHub (pinned to a7de90d38a)
Solutions
- Verify SurrealDB is running (make database / make status) and the API could reach it at startup
- Inspect logs — logger.exception(e) prints the original traceback; fix the underlying cause
- If it's deserialization, compare the model's Pydantic fields against actual records (schema drift) and let migrations run or fix the data
- Catch DatabaseOperationError at the API layer and return a 503/500 rather than crashing
Example fix
// before
objects = await Note.get_all() # raises DatabaseOperationError bare
// after
from open_notebook.domain.errors import DatabaseOperationError
try:
objects = await Note.get_all()
except DatabaseOperationError as e:
logger.error(f"DB unavailable: {e}")
objects = [] Defensive patterns
Strategy: try-catch
Validate before calling
null
Try / catch
from open_notebook.domain.errors import DatabaseOperationError
try:
items = await Note.get_all()
except DatabaseOperationError as e:
logger.exception("get_all failed", exc_info=e)
raise HTTPException(status_code=503, detail="Database temporarily unavailable") Prevention
- Start tiers in order: database → api → worker → frontend (make start-all)
- Watch API startup logs to confirm migrations ran
- Monitor SurrealDB health; alert on connection errors before they reach user paths
When it happens
Trigger: SurrealDB is down or unreachable; the record shape doesn't match the model's Pydantic fields (schema drift after a migration); connection timeout; permission errors on the table. The exception's __cause__ holds the original error.
Common situations: Forgot to run `make database` before the API, schema migrations didn't run on startup (check API logs), a model field was renamed in Python but not migrated in SurrealDB, or stale docker container with old schema.
Related errors
- Error saving record: {e}
- Failed to delete {self.__class__.table_name}
- Search failed: {str(e)}
- Failed to load default models configuration
- Failed to create record
AI-assisted analysis of lfnovo/open-notebook@a7de90d38a (2026-08-27).
Data as JSON: /api/errors/d8cfc5f7b42cc6eb.
Report an issue: GitHub.