{"record":{"id":"edb67d03a078a7f7","repo":"siyuan-note/siyuan","slug":"snapshot-version-is-not-a-document","errorCode":null,"errorMessage":"snapshot version is not a document","messagePattern":"snapshot version is not a document","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/history_diff.go","lineNumber":413,"sourceCode":"}\n\nfunc loadSnapshotDocVersion(fileID string) (ret *loadedDocVersion, err error) {\n\tif \"\" == fileID {\n\t\treturn nil, errors.New(\"snapshot file ID is required\")\n\t}\n\tif 1 > len(Conf.Repo.Key) {\n\t\treturn nil, errors.New(Conf.Language(26))\n\t}\n\trepo, err := newRepository()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfile, err := repo.GetFile(fileID)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif !strings.HasSuffix(strings.ToLower(file.Path), \".sy\") {\n\t\treturn nil, errors.New(\"snapshot version is not a document\")\n\t}\n\trepoPath := strings.TrimPrefix(file.Path, \"/\")\n\tpathParts := strings.SplitN(repoPath, \"/\", 2)\n\tdata, err := repo.OpenFile(file)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tciphertext := util.IsCiphertext(data)\n\tif ciphertext {\n\t\tif len(pathParts) < 2 || !ast.IsNodeIDPattern(pathParts[0]) || !IsEncryptedBox(pathParts[0]) {\n\t\t\treturn nil, errors.New(\"encrypted snapshot document is missing valid notebook context\")\n\t\t}\n\t\tHoldBoxReadLock(pathParts[0])\n\t\tdefer ReleaseBoxReadLock(pathParts[0])\n\t\tdek, unlockErr := GetDEKIfUnlocked(pathParts[0])\n\t\tif unlockErr != nil {\n\t\t\treturn nil, errors.New(Conf.Language(314))\n\t\t}","sourceCodeStart":395,"sourceCodeEnd":431,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/history_diff.go#L395-L431","documentation":"After resolving the file ID to a repo file, loadSnapshotDocVersion verifies the file's stored path ends with .sy (case-insensitive). Snapshot diffs are only supported for documents; if the snapshot object is an asset or any non-document file, this error is thrown.","triggerScenarios":"loadDocVersion in snapshot mode with a fileID whose repo file path is not a .sy document, e.g. an asset snapshot or index file stored in the repo.","commonSituations":"Passing an asset's file ID where a document's file ID is expected (IDs copied from the wrong history entry); older snapshot entries for assets being diffed; a script iterating repo files and assuming all are documents.","solutions":["Use the file ID of a document snapshot (path ending in .sy) from the repo file listing.","Filter repo files by .sy path suffix before requesting version diffs.","For asset history, use the asset history APIs instead of the document version loader.","Re-select the history entry in the UI to get the correct document file ID."],"exampleFix":"// before\nloadDocVersion(fileID_of_asset.png) -> \"snapshot version is not a document\"\n// after\nloadDocVersion(fileID_of_document.sy)","handlingStrategy":"validation","validationCode":"// JS: only request diffs for .sy snapshot entries\nif (!file.path.toLowerCase().endsWith(\".sy\")) return;\nreturn fetchPost(\"/api/history/loadDocVersion\", { fileID: file.id });","typeGuard":"function isDocSnapshot(file) { return typeof file.path === \"string\" && file.path.toLowerCase().endsWith(\".sy\"); }","tryCatchPattern":"catch (e) { if (e.message === \"snapshot version is not a document\") { selectDocumentSnapshotInstead(); } else { throw e; } }","preventionTips":["Filter repo/history entries to .sy paths before diffing","Do not pass asset file IDs to document version APIs","When scripting, check the file path suffix before each call"],"tags":["snapshot","repo","document","type-mismatch"],"backgroundTag":"incompatible-source-type","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}