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
- Verify the annotationID exists as a key in the .sya JSON and has a valid page/index integer >= 0
- Recreate the annotation in the PDF so the sidecar regenerates a valid entry
- Restore the .sya from version history if fields were removed by editing
- 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
- Recreate annotations instead of editing their IDs in the document text
- Re-check references after re-annotating a PDF with a different tool
- Clean up document references when deleting annotations
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
- invalid file annotation reference
- resolve file annotation asset
- decrypt file annotation
- export artifact [ ] is a directory
- export path is outside export directory
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)