grafana/grafana · error · Error

Annotation '${name}' already exists

Error message

Annotation '${name}' already exists

What it means

Thrown by the ADD_ANNOTATION dashboard-scene mutation command when a new annotation layer's spec.name collides with an existing annotation layer in the dashboard's annotation layer set. The command is wrapped in try/catch and converts the thrown Error into a { success:false, error } result, so callers see a failed mutation result rather than a propagated exception.

Source

Thrown at public/app/features/dashboard-scene/mutation-api/commands/addAnnotation.ts:42

  name: 'ADD_ANNOTATION',
  description: payloads.addAnnotation.description ?? '',

  payloadSchema: payloads.addAnnotation,
  permission: requiresEdit,
  readOnly: false,

  handler: async (payload, context) => {
    const { scene } = context;
    enterEditModeIfNeeded(scene);

    try {
      // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Zod output is structurally compatible with AnnotationQueryKind
      const annotation = payload.annotation as AnnotationQueryKind;
      const name = annotation.spec.name;
      const set = getAnnotationLayerSet(scene);

      if (findAnnotationLayer(set, name)) {
        throw new Error(`Annotation '${name}' already exists`);
      }

      if (annotation.spec.builtIn && hasBuiltInAnnotation(set)) {
        throw new Error('Dashboard already has a built-in annotation layer');
      }

      const newLayer = buildAnnotationLayer(annotation);
      const updated = [...set.state.annotationLayers];
      const { position } = payload;

      if (position !== undefined && position >= 0 && position < updated.length) {
        updated.splice(position, 0, newLayer);
      } else {
        updated.push(newLayer);
      }

      replaceAnnotationLayers(set, updated);

View on GitHub (pinned to ae3104e369)

Solutions

  1. Choose a unique annotation layer name (check findAnnotationLayer(set, name) first).
  2. If overwriting was intended, use the update/replace command instead of ADD_ANNOTATION.
  3. Surface the returned result.error in the UI when success === false.
  4. In tests, use unique names per command.

Example fix

// before
const res = await runMutation({ type: 'ADD_ANNOTATION', annotation });
// after
const set = getAnnotationLayerSet(scene);
if (findAnnotationLayer(set, annotation.spec.name)) {
  notify.error(`Annotation '${annotation.spec.name}' already exists`);
  return;
}
const res = await runMutation({ type: 'ADD_ANNOTATION', annotation });
Defensive patterns

Strategy: validation

Validate before calling

const set = getAnnotationLayerSet(scene);
if (findAnnotationLayer(set, annotation.spec.name)) {
  notify.error(`Annotation '${annotation.spec.name}' already exists`);
  return;
}

Type guard

const isUniqueAnnotationName = (set, name): boolean =>
  !findAnnotationLayer(set, name);

Try / catch

const res = await runMutation({ type: 'ADD_ANNOTATION', annotation });
if (!res.success) {
  notify.error(res.error);
}

Prevention

When it happens

Trigger: Issuing ADD_ANNOTATION with payload.annotation.spec.name equal to the spec.name of an existing layer in getAnnotationLayerSet(scene).state.annotationLayers.

Common situations: User creates an annotation layer with a duplicate name; programmatic dashboards issuing multiple ADD_ANNOTATION commands with the same name; copy-paste of annotation specs; tests that re-use a name without clearing the set.

Related errors


AI-assisted analysis of grafana/grafana@ae3104e369 (2026-08-12). Data as JSON: /api/errors/0d8b0668c5bb7c85. Report an issue: GitHub.