siyuan-note/siyuan · error

missing or invalid annotation

Error message

missing or invalid annotation [%s] in [%s]

What it means

After parsing the .sya JSON, the kernel looks up the requested annotationID; the entry must exist and carry a usable page number (either "page" or pages[0].index, not null and >= 0). Missing ID or invalid page data aborts the export with this error.

Solutions

  1. Verify the annotationID exists as a key in the .sya JSON and has a valid page/index integer >= 0
  2. Recreate the annotation in the PDF so the sidecar regenerates a valid entry
  3. Restore the .sya from version history if fields were removed by editing
  4. Update the document's annotation reference to point to an existing annotation ID

Example fix

// before: missing page in sidecar entry
{"ann-1": {}}
// after
{"ann-1": {"page": 0}}
Defensive patterns

Strategy: validation

Validate before calling

function annotationIsExportable(syaJSON, annotationID) {
  const a = syaJSON[annotationID];
  if (!a) return false;
  const idx = a.pages && a.pages.length ? a.pages[0].index : a.page;
  return typeof idx === "number" && idx >= 0;
}

Type guard

function hasValidPage(a) {
  const idx = a?.pages?.[0]?.index ?? a?.page;
  return typeof idx === "number" && Number.isInteger(idx) && idx >= 0;
}

Try / catch

try {
  await exportAnnotation(docID);
} catch (e) {
  if (/missing or invalid annotation/.test(e.message)) {
    // recreate the annotation or export without it
    console.warn("Skipping invalid annotation", e.message);
  }
}

Prevention

When it happens

Trigger: Exporting an annotation whose ID is not present in the parsed .sya map; the entry has neither page nor pages[0].index (both null); the resolved page index is negative.

Common situations: Stale annotation reference in the document after the annotation was deleted from the PDF; hand-edited .sya missing fields; annotation IDs changed when the PDF was re-annotated with a different tool.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/656565541d543ddb. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/export.go:4398

		}
		syaData = plain
	}
	syaJSON := map[string]struct {
		Pages []struct {
			Index *int `json:"index"`
		} `json:"pages"`
		Page *int `json:"page"`
	}{}
	if err = gulu.JSON.UnmarshalJSON(syaData, &syaJSON); err != nil {
		return fmt.Errorf("parse file annotation [%s]: %w", sya, err)
	}
	annotationData, found := syaJSON[annotationID]
	pageIndex := annotationData.Page
	if 0 < len(annotationData.Pages) {
		pageIndex = annotationData.Pages[0].Index
	}
	if !found || nil == pageIndex || *pageIndex < 0 {
		return fmt.Errorf("missing or invalid annotation [%s] in [%s]", annotationID, sya)
	}
	pageStr := strconv.Itoa(*pageIndex + 1)

	refText := n.TextMarkTextContent
	ext := filepath.Ext(p)
	file := strings.TrimPrefix(strings.TrimSuffix(p, ext), "assets/")
	// 仅剥离完整的节点 ID 后缀,无后缀文件及短文件名保持原样。
	if len(file) > 23 && file[len(file)-23] == '-' && ast.IsNodeIDPattern(file[len(file)-22:]) {
		file = file[:len(file)-23]
	}
	file += ext
	fileAnnotationRefLink := &ast.Node{Type: ast.NodeLink}
	fileAnnotationRefLink.AppendChild(&ast.Node{Type: ast.NodeOpenBracket})
	if 0 == fileAnnotationRefMode {
		fileAnnotationRefLink.AppendChild(&ast.Node{Type: ast.NodeLinkText, Tokens: []byte(file + " - p" + pageStr + " - " + refText)})
	} else {
		fileAnnotationRefLink.AppendChild(&ast.Node{Type: ast.NodeLinkText, Tokens: []byte(refText)})
	}

View on GitHub (pinned to 9f775e8a12)