lfnovo/open-notebook · critical · DatabaseOperationError

Failed to delete

Error message

Failed to delete {self.__class__.table_name}

What it means

delete() wraps repo_delete in try/except and converts any failure into DatabaseOperationError('Failed to delete {table}'). The original error is logged (with the record id) but not attached to the raised message, so logs are the place to find the root cause.

Solutions

  1. Check the API logs for the 'Error deleting ...' line to get the underlying cause
  2. Verify SurrealDB connectivity and retry — transient failures often clear
  3. Catch DatabaseOperationError in the endpoint and return 503 with a retry hint to the client
  4. If 'already gone' races are common, treat subsequent NotFoundError on re-check as success (idempotent delete)

Example fix

# before
await note.delete()  # unhandled

# after
from open_notebook.domain.errors import DatabaseOperationError
try:
    await note.delete()
except DatabaseOperationError:
    raise HTTPException(status_code=503, detail="Delete failed, retry shortly")
Defensive patterns

Strategy: retry

Try / catch

from open_notebook.domain.errors import DatabaseOperationError, NotFoundError
try:
    await note.delete()
except DatabaseOperationError:
    try:
        await Note.get(note.id)  # idempotency check
    except NotFoundError:
        pass  # already deleted; treat as success
    else:
        raise HTTPException(status_code=503, detail="Delete failed, retry")

Prevention

When it happens

Trigger: SurrealDB unreachable during delete, record already deleted server-side causing an error path in the driver, permission failures, or graph-relate edges blocking removal. Logged line 'Error deleting {table} with id ...' carries the details.

Common situations: DB tier down when a user hits delete; network blip between API and SurrealDB; deletion racing with another process that already removed the record.

Related errors


AI-assisted analysis of lfnovo/open-notebook@a7de90d38a (2026-08-27). Data as JSON: /api/errors/188b312d9d70c676. Report an issue: GitHub.

Appendix: source

Thrown at open_notebook/domain/base.py:215

    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)}"
            )
            raise DatabaseOperationError(
                f"Failed to delete {self.__class__.table_name}"
            )

    async def relate(
        self, relationship: str, target_id: str, data: Optional[Dict] = {}
    ) -> Any:
        if not relationship or not target_id or not self.id:
            raise InvalidInputError("Relationship and target ID must be provided")
        try:
            return await repo_relate(
                source=self.id, relationship=relationship, target=target_id, data=data
            )
        except Exception as e:
            logger.error(f"Error creating relationship: {str(e)}")
            logger.exception(e)
            raise DatabaseOperationError(e)

    @field_validator("created", "updated", mode="before")

View on GitHub (pinned to a7de90d38a)