lfnovo/open-notebook · error · InvalidInputError

ID cannot be empty

Error message

ID cannot be empty

What it means

ObjectModel.get(id) rejects empty/falsy IDs up front with InvalidInputError before touching the database. An empty string, None, or otherwise falsy id can never name a record, so the method fails fast.

Source

Thrown at open_notebook/domain/base.py:107

            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)

            result = await repo_query("SELECT * FROM $id", {"id": ensure_record_id(id)})
            if result:
                return target_class(**result[0])
            else:

View on GitHub (pinned to a7de90d38a)

Solutions

  1. Validate/require the id at the API boundary (Path(..., min_length=1) in FastAPI)
  2. Default to a 404 or 400 response when the id is missing instead of calling get()
  3. Check truthiness before calling: if not id: raise HTTPException(404)

Example fix

# before
obj = await Note.get(note_id)  # note_id may be ''

# after
if not note_id:
    raise HTTPException(status_code=404, detail="Note id required")
obj = await Note.get(note_id)
Defensive patterns

Strategy: validation

Validate before calling

if not id or not isinstance(id, str):
    raise HTTPException(status_code=404, detail="Missing id")
obj = await Note.get(id)

Type guard

def is_valid_record_id(id: object) -> bool:
    return isinstance(id, str) and bool(id.strip()) and ":" in id

Prevention

When it happens

Trigger: await MyModel.get(''), await MyModel.get(None), or a value pulled from an unvalidated request path/query param like /notes/ that arrives as empty string.

Common situations: API route handlers passing through unvalidated path parameters; frontend sending undefined which serializes to ''; default arguments like id='' used as placeholders.

Understand the failure class

Background: Missing required parameter errors: what 'X is required' and 'the required X param is missing' mean, and how to fix them — this error's family across 27 libraries.

Related errors


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