apache/superset · error · AnnotationLayerNotFoundError

Annotation layer not found.

Error message

Annotation layer not found.

What it means

Raised by AnnotationCreateCommand.validate() (create.py:57) when the 'layer' property is missing/falsy or not an integer, i.e. the request did not reference an annotation layer id at all. AnnotationLayerNotFoundError (a CommandException) normally maps to 404 in the REST layer. It fires before the DAO lookup, so the layer id never even hits the database.

Source

Thrown at superset/commands/annotation_layer/annotation/create.py:57

class CreateAnnotationCommand(BaseCommand):
    def __init__(self, data: dict[str, Any]):
        self._properties = data.copy()

    @transaction(on_error=partial(on_error, reraise=AnnotationCreateFailedError))
    def run(self) -> Model:
        self.validate()
        return AnnotationDAO.create(attributes=self._properties)

    def validate(self) -> None:
        exceptions: list[ValidationError] = []
        layer_id: Optional[int] = self._properties.get("layer")
        start_dttm: Optional[datetime] = self._properties.get("start_dttm")
        end_dttm: Optional[datetime] = self._properties.get("end_dttm")
        short_descr = self._properties.get("short_descr", "")

        # Validate/populate model exists
        if not layer_id and not isinstance(layer_id, int):
            raise AnnotationLayerNotFoundError()
        annotation_layer = AnnotationLayerDAO.find_by_id(layer_id)
        if not annotation_layer:
            raise AnnotationLayerNotFoundError()
        self._properties["layer"] = annotation_layer

        # Validate short descr uniqueness on this layer
        if not AnnotationDAO.validate_update_uniqueness(layer_id, short_descr):
            exceptions.append(AnnotationUniquenessValidationError())

        # validate date time sanity
        if start_dttm and end_dttm and end_dttm < start_dttm:
            exceptions.append(AnnotationDatesValidationError())

        if exceptions:
            raise AnnotationInvalidError(exceptions=exceptions)

View on GitHub (pinned to f4587218dd)

Solutions

  1. Include an integer 'layer' field (the annotation layer id) in the POST /api/v1/annotation/ payload.
  2. Fetch valid layer ids first with GET /api/v1/annotation_layer/ and populate a required selector in the UI.
  3. Validate the payload client-side before submit so layer is always a positive integer.

Example fix

# before
POST /api/v1/annotation/
{"short_descr": "launch", "start_dttm": "2026-01-01T00:0000", "end_dttm": "2026-01-02T00:00:00"}

# after
POST /api/v1/annotation/
{"layer": 1, "short_descr": "launch", "start_dttm": "2026-01-01T00:00:00", "end_dttm": "2026-01-02T00:00:00"}
Defensive patterns

Strategy: validation

Validate before calling

def valid_annotation_layer_ref(payload: dict) -> bool:
    layer = payload.get("layer")
    return isinstance(layer, int) and not isinstance(layer, bool) and layer > 0

if not valid_annotation_layer_ref(payload):
    raise RequestValidationError("'layer' must be a positive integer annotation layer id")

Type guard

def has_int_layer(payload: dict) -> TypeGuard[dict]:
    return isinstance(payload.get("layer"), int)

Try / catch

try:
    CreateAnnotationCommand(properties).run()
except AnnotationLayerNotFoundError:
    return {"error": "annotation layer missing or unknown"}, 404

Prevention

When it happens

Trigger: POST /api/v1/annotation/ with a body omitting 'layer' or setting it to null/'' /a non-int value; programmatic creation from a form where the layer selector was left empty.

Common situations: Frontend form submits before the user picks a layer; API clients modeled on annotation layer endpoints that assume layer is optional; marshmallow schema coercion differences turning a valid id into a string.

Related errors


AI-assisted analysis of apache/superset@f4587218dd (2026-08-14). Data as JSON: /api/errors/931329fe1a576e62. Report an issue: GitHub.