siyuan-note/siyuan · error
resolve file annotation asset
Error message
resolve file annotation asset [%s]: %w
What it means
During PDF file-annotation export, the kernel resolves the asset link referenced by an annotation to an absolute path inside a notebook via GetAssetAbsPathInBox. When that lookup fails (asset missing, link malformed, or asset outside the box), export of that file annotation is aborted with this wrapped error, preserving the original source rather than exporting incomplete data.
Solutions
- Verify the asset file exists in the notebook's assets folder at the path referenced by the annotation link
- Re-insert or re-link the PDF annotation so the asset link points to an existing asset
- Check the notebook (boxID) matches the notebook that actually owns the asset
- Rebuild the asset reference by re-uploading the PDF and recreating the annotation
Example fix
// before: annotation points to a deleted asset  // after: re-link to the existing asset 
Defensive patterns
Strategy: validation
Validate before calling
const assetPath = "assets/report.pdf";
const resp = await fetchPost("/api/filetree/getDocInfo", {id: docID}); // confirm annotation link resolves
// ensure the file exists before export:
const stat = await fetchPost("/api/file/getFileStat", {path: assetPath}); Try / catch
try {
await exportAnnotation(docID);
} catch (e) {
if (/resolve file annotation asset/.test(e.message)) {
console.warn("Asset missing; re-link the PDF before exporting", e.cause);
}
} Prevention
- Never delete or move PDFs referenced by file annotations without re-linking
- Keep annotation assets inside the owning notebook's assets folder
- Run export after confirming notebooks are fully synced
When it happens
Trigger: Calling the export path for a PDF whose .sya annotation asset link cannot be resolved: the asset was moved/renamed/deleted from the notebook's assets folder, the lookupLink is malformed (bad query suffix), or the asset belongs to a different box than boxID.
Common situations: Exporting a document after the referenced PDF was deleted or moved out of assets/; assets synced from another device where the file was removed; hand-edited markdown pointing to a wrong asset path; notebook ID mismatch when exporting across boxes.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- invalid file annotation reference
- missing or invalid annotation
- Conf.Language(14) (copy assets failed: )
- decrypt file annotation
- parse file annotation
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/0ac9f1081018fdbe.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/export.go:4357
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"
// 以实际资源所属笔记本认证标注密文,读取失败时保留源文件并中止导出。
assetBoxID := ExtractBoxIDFromAssetsPath(absPath)
var dek []byte
if IsEncryptedBox(assetBoxID) {
HoldBoxReadLock(assetBoxID)
defer ReleaseBoxReadLock(assetBoxID)
dek, err = GetDEKIfUnlocked(assetBoxID)
if err != nil {
return err
}
defer clear(dek)
}
syaData, readErr := os.ReadFile(sya)
if readErr != nil {
return fmt.Errorf("read file annotation [%s]: %w", sya, readErr)
}View on GitHub (pinned to 9f775e8a12)