lfnovo/open-notebook · warning · NotFoundError

{table_name} with id {id} not found

Error message

{table_name} with id {id} not found

What it means

get(id) executed the query successfully but SurrealDB returned no row for the given record id, so there is nothing to deserialize and NotFoundError is raised. This is the normal 'record does not exist' signal, not an infrastructure failure.

Source

Thrown at open_notebook/domain/base.py:126

        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)

            result = await repo_query("SELECT * FROM $id", {"id": ensure_record_id(id)})
            if result:
                return target_class(**result[0])
            else:
                raise NotFoundError(f"{table_name} with id {id} not found")
        except Exception as e:
            logger.error(f"Error fetching object with id {id}: {str(e)}")
            logger.exception(e)
            raise NotFoundError(f"Object with id {id} not found - {str(e)}")

    @classmethod
    def _get_class_by_table_name(cls, table_name: str) -> Optional[Type["ObjectModel"]]:
        """Find the appropriate subclass based on table_name."""

        def get_all_subclasses(c: Type["ObjectModel"]) -> List[Type["ObjectModel"]]:
            all_subclasses: List[Type["ObjectModel"]] = []
            for subclass in c.__subclasses__():
                all_subclasses.append(subclass)
                all_subclasses.extend(get_all_subclasses(subclass))
            return all_subclasses

        for subclass in get_all_subclasses(ObjectModel):
            if hasattr(subclass, "table_name") and subclass.table_name == table_name:

View on GitHub (pinned to a7de90d38a)

Solutions

  1. Catch NotFoundError and surface a 404 to the user
  2. If the id came from a cached list, refresh the list / purge stale ids
  3. Verify the id by listing records in that table first when debugging

Example fix

# before
note = await Note.get(note_id)  # unhandled NotFoundError

# after
from open_notebook.domain.errors import NotFoundError
try:
    note = await Note.get(note_id)
except NotFoundError:
    raise HTTPException(status_code=404, detail="Note not found")
Defensive patterns

Strategy: try-catch

Try / catch

from open_notebook.domain.errors import NotFoundError
try:
    note = await Note.get(note_id)
except NotFoundError:
    raise HTTPException(status_code=404, detail="Note not found")

Prevention

When it happens

Trigger: await Note.get('note:abc') where that record was deleted or never existed; race where another process deleted the row between listing and get; id copied with a wrong/typo'd key portion.

Common situations: Stale ids cached in the frontend or embedded in notebook cells/queues after the source was deleted; user follows an old link; concurrent cleanup jobs.

Related errors


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