siyuan-note/siyuan · error

invalid file annotation reference

Error message

invalid file annotation reference [%s]

What it means

processFileAnnotationRef parses a file-annotation reference of the form produced by util.SplitFileAnnotationRef. If the refID does not contain a valid annotation ID portion (empty after splitting), the reference is malformed and the export fails with 'invalid file annotation reference [%s]'.

Solutions

  1. Fix or remove the malformed file annotation reference in the source document (re-insert the annotation from the PDF asset)
  2. Check the refID format: it must be '<assetPath>@<annotationID>'; regenerate the link via the UI's file annotation feature
  3. If encountered in bulk, validate all file-annotation-ref attributes in the notebook and repair or strip invalid ones

Example fix

// before
<span data-type="file-annotation-ref" data-id="assets/paper.pdf@">text</span> // empty annotation id
// after
<span data-type="file-annotation-ref" data-id="assets/paper.pdf@page=2&loc=...">text</span>
Defensive patterns

Strategy: type-guard

Validate before calling

function isValidFileAnnotationRef(refId) {
  const idx = refId.indexOf('@');
  return idx > 0 && refId.slice(idx + 1).length > 0;
}

Type guard

const hasAnnotationID = ref => typeof ref === 'string' && ref.split('@').length === 2 && ref.split('@')[1] !== '';

Try / catch

try { await exportPDF(id); }
catch (e) {
  const m = String(e).match(/invalid file annotation reference \[(.+)\]/);
  if (m) { repairOrRemoveAnnotationRef(m[1]); await retryExport(); }
}

Prevention

When it happens

Trigger: Export (PDF/annotation processing) encounters a node whose file-annotation-ref attribute holds a string that splits into an empty annotationID — e.g. truncated, hand-edited, or plugin-written refID without the '@'-separated annotation id part.

Common situations: Document content edited by an older/plugin version writing malformed annotation refs; PDF asset replaced so annotation links got corrupted; manual editing of .sy content breaking the ref format.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


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

Appendix: source

Thrown at kernel/model/export.go:4341

		if n.ID == id {
			ret = true
			return ast.WalkStop
		}
		return ast.WalkContinue
	})
	return
}

type refAsFootnotes struct {
	refNum        string
	refAnchorText string
}

func processFileAnnotationRef(refID string, n *ast.Node, fileAnnotationRefMode int, boxID string) error {
	assetLink, annotationID := util.SplitFileAnnotationRef(refID)
	if "" == annotationID {
		return fmt.Errorf("invalid file annotation reference [%s]", refID)
	}
	p, query, _ := splitAssetReference(assetLink)
	assetLink = p
	if "" != query {
		assetLink += "?" + query
	}
	lookupLink := p
	if decodedPath, decodeErr := url.PathUnescape(p); nil == decodeErr {
		lookupLink = decodedPath
	}
	if "" != query {
		lookupLink += "?" + query
	}
	absPath, err := GetAssetAbsPathInBox(lookupLink, boxID)
	if err != nil {
		return fmt.Errorf("resolve file annotation asset [%s]: %w", assetLink, err)
	}
	sya := absPath + ".sya"

View on GitHub (pinned to 9f775e8a12)