apache/superset · error · AnnotationLayerNotFoundError

Annotation layer not found.

Error message

Annotation layer not found.

What it means

AnnotationLayerNotFoundError raised inside UpdateAnnotationCommand.validate() (update.py:66): the PATCH payload includes a 'layer' id, but AnnotationLayerDAO.find_by_id(layer_id) returned None — the annotation is being moved to a layer that does not exist. HTTP 404. Note only a supplied layer triggers the lookup; omitting 'layer' keeps the current layer.

Source

Thrown at superset/commands/annotation_layer/annotation/update.py:66

    def run(self) -> Model:
        self.validate()
        assert self._model
        return AnnotationDAO.update(self._model, self._properties)

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

        # Validate/populate model exists
        self._model = AnnotationDAO.find_by_id(self._model_id)
        if not self._model:
            raise AnnotationNotFoundError()
        # Validate/populate layer exists
        if layer_id:
            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,
                annotation_id=self._model_id,
            ):
                exceptions.append(AnnotationUniquenessValidationError())
        else:
            self._properties["layer"] = self._model.layer

        # validate date time sanity
        start_dttm: Optional[datetime] = self._properties.get("start_dttm")
        end_dttm: Optional[datetime] = self._properties.get("end_dttm")

        if start_dttm and end_dttm and end_dttm < start_dttm:
            exceptions.append(AnnotationDatesValidationError())

View on GitHub (pinned to f4587218dd)

Solutions

  1. Verify the destination layer exists (GET /api/v1/annotation_layer/<id>) before including 'layer' in the PATCH.
  2. If moving is optional, omit 'layer' from the payload to leave the annotation on its current layer.
  3. Refresh layer options in the UI right before the move operation.

Example fix

# before
PATCH /api/v1/annotation/42 {"layer": 7}  # layer 7 deleted

# after
PATCH /api/v1/annotation/42 {"short_descr": "renamed"}  # keep current layer
# or pick a live layer id after verifying via GET /api/v1/annotation_layer/
Defensive patterns

Strategy: validation

Validate before calling

from superset.daos.annotation_layer import AnnotationLayerDAO

if "layer" in properties:
    assert AnnotationLayerDAO.find_by_id(properties["layer"]) is not None, "target layer missing"

Try / catch

try:
    UpdateAnnotationCommand(model_id, properties).run()
except AnnotationLayerNotFoundError:
    layers = fetch_live_layers(); reselect_target_layer(layers)

Prevention

When it happens

Trigger: PATCH /api/v1/annotation/<id> with {"layer": <deleted-or-foreign id>}; drag-and-drop move of an annotation to a layer removed moments earlier.

Common situations: Layer deleted concurrently while its annotations were being reorganized; ids copied between staging and prod; stale layer pickers.

Related errors


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