lfnovo/open-notebook · critical · DatabaseOperationError
Error saving record: {e}
Error message
Error saving record: {e} What it means
save() re-raises InvalidInputError/RuntimeTime transaction conflicts untouched but wraps every other unexpected exception in DatabaseOperationError after logging 'Error saving record: {e}'. It indicates the write to SurrealDB or record serialization failed at the infrastructure level.
Source
Thrown at open_notebook/domain/base.py:195
result_list: List[Dict[str, Any]] = (
repo_result if isinstance(repo_result, list) else [repo_result]
)
for key, value in result_list[0].items():
if hasattr(self, key):
if isinstance(getattr(self, key), BaseModel):
setattr(self, key, type(getattr(self, key))(**value))
else:
setattr(self, key, value)
except ValidationError as e:
logger.error(f"Validation failed: {e}")
raise
except RuntimeError:
# Transaction conflicts should propagate for retry
raise
except Exception as e:
logger.error(f"Error saving record: {e}")
raise DatabaseOperationError(e)
def _prepare_save_data(self) -> Dict[str, Any]:
data = self.model_dump()
return {
key: value
for key, value in data.items()
if value is not None or key in self.__class__.nullable_fields
}
async def delete(self) -> bool:
if self.id is None:
raise InvalidInputError("Cannot delete object without an ID")
try:
logger.debug(f"Deleting record with id {self.id}")
return await repo_delete(self.id)
except Exception as e:
logger.error(
f"Error deleting {self.__class__.table_name} with id {self.id}: {str(e)}"View on GitHub (pinned to a7de90d38a)
Solutions
- Check SurrealDB is up and the API connected at startup (make status)
- Inspect logs / e.__cause__ for the server's rejection reason
- If type-related, ensure model fields are JSON-serializable (datetime, str, list, dict)
- Catch DatabaseOperationError in callers and decide on retry vs user-facing error
Example fix
# before
await note.save() # unhandled DatabaseOperationError
# after
from open_notebook.domain.errors import DatabaseOperationError
try:
await note.save()
except DatabaseOperationError as e:
logger.error(f"save failed: {e}")
raise HTTPException(status_code=503, detail="Could not save note") Defensive patterns
Strategy: retry
Validate before calling
null
Try / catch
from open_notebook.domain.errors import DatabaseOperationError
for attempt in range(3):
try:
await note.save()
break
except DatabaseOperationError:
if attempt == 2:
raise HTTPException(status_code=503, detail="Could not save")
await asyncio.sleep(2 ** attempt) Prevention
- Verify SurrealDB is reachable before write-heavy flows
- Keep model fields JSON-serializable; test round-trip save+get in CI
- Retry transient failures with backoff; only surface to users after retries
When it happens
Trigger: SurrealDB unreachable, unique-constraint/style server rejections, serialization failures on field types, or invalid record data the server refuses. The original exception is attached as the cause for inspection.
Common situations: DB container stopped mid-run; model fields holding types SurrealDB can't store (e.g. arbitrary objects); concurrent writes hitting server-side limits; running the worker without the database tier up.
Related errors
- Error fetching all {cls.table_name}: {str(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/b6ec98343b07f773.
Report an issue: GitHub.