lfnovo/open-notebook · error · InvalidInputError

No class found for table {table_name}

Error message

No class found for table {table_name}

What it means

When get(id) is called and the table name embedded in the record id (the part before the first ':') does not match the calling class, the method searches all registered ObjectModel subclasses via _get_class_by_table_name. If no subclass declares that table_name, there is no model to deserialize the row into, so it raises InvalidInputError.

Source

Thrown at open_notebook/domain/base.py:119

            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)

            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"]] = []

View on GitHub (pinned to a7de90d38a)

Solutions

  1. Check the id's table prefix matches a real model (everything before the first ':')
  2. Ensure the model module is imported so the subclass is discoverable
  3. If the table was renamed, update the stored ids or add a compatibility mapping
  4. Prefer calling get() on the specific class whose table matches the id

Example fix

# before
obj = await ObjectModel.get(f"{table}:{rid}")  # table may be unknown

# after
from open_notebook.domain.model import Note
obj = await Note.get(f"note:{rid}")
Defensive patterns

Strategy: type-guard

Validate before calling

table = rid.split(":", 1)[0]
if table not in KNOWN_TABLES:  # {'note', 'source', ...}
    raise HTTPException(status_code=400, detail=f"Unknown table '{table}'")

Type guard

KNOWN = {c.table_name for c in ObjectModel.__subclasses__()}  # after imports

def table_is_registered(rid: str) -> bool:
    return rid.split(":", 1)[0] in {c.table_name for c in all_subclasses(ObjectModel)}

Try / catch

from open_notebook.domain.errors import InvalidInputError
try:
    obj = await ObjectModel.get(rid)
except InvalidInputError as e:
    raise HTTPException(status_code=400, detail=str(e))

Prevention

When it happens

Trigger: await ObjectModel.get('sometable:abc123') where no model subclass has table_name='sometable'; typo'd table prefix in an id string; a model class that exists but was never imported (so not in the subclass registry).

Common situations: Ids constructed by string concatenation with a wrong table prefix; model module not imported anywhere so __subclasses__ never includes it; renamed table_name in a model while old ids still circulate in stored data or queues.

Related errors


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