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
- Verify the destination layer exists (GET /api/v1/annotation_layer/<id>) before including 'layer' in the PATCH.
- If moving is optional, omit 'layer' from the payload to leave the annotation on its current layer.
- 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
- Confirm the destination layer via GET before moving an annotation.
- Omit 'layer' from PATCH payloads when not moving the annotation.
- Refresh layer pickers immediately before move operations.
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
- Annotation not found.
- Annotation layer not found.
- Annotation not found.
- Annotation parameters are invalid.
- Annotation layer not found.
AI-assisted analysis of apache/superset@f4587218dd (2026-08-14).
Data as JSON: /api/errors/a1ab8b4a6a140422.
Report an issue: GitHub.