{"record":{"id":"2f58c2dfba6559ae","repo":"siyuan-note/siyuan","slug":"conf-language-26","errorCode":null,"errorMessage":"Conf.Language(26)","messagePattern":"Conf\\.Language\\(26\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/repository.go","lineNumber":204,"sourceCode":"\t\t}\n\t\tpurgeCancelMu.Unlock()\n\t}()\n\n\t_, err = repo.Purge(cancelCtx, retentionIndexIDs...)\n}\n\nfunc cancelPurge() {\n\tpurgeCancelMu.Lock()\n\tdefer purgeCancelMu.Unlock()\n\tif nil != purgeCancel {\n\t\tpurgeCancel()\n\t\tpurgeCancel = nil\n\t}\n}\n\nfunc GetRepoFile(fileID string) (ret []byte, p string, err error) {\n\tif 1 > len(Conf.Repo.Key) {\n\t\terr = errors.New(Conf.Language(26))\n\t\treturn\n\t}\n\n\tret, file, err := readRepoFileWithAssets(fileID)\n\tif err != nil {\n\t\treturn\n\t}\n\tret, err = decryptRepoDataIfNeeded(ret, file.Path)\n\tp = file.Path\n\treturn\n}\n\n// ResolveRepoFileBoxID 返回仓库文件路径中明确记录的加密笔记本 ID。\nfunc ResolveRepoFileBoxID(fileID string) (boxID string, err error) {\n\tif 1 > len(Conf.Repo.Key) {\n\t\treturn \"\", errors.New(Conf.Language(26))\n\t}\n\trepo, err := newRepository()","sourceCodeStart":186,"sourceCodeEnd":222,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/repository.go#L186-L222","documentation":"GetRepoFile returns the localized Conf.Language(26) message (repo key not set) when the data repository encryption key is not configured (Conf.Repo.Key is empty). Snapshots in SiYuan's repo are encrypted, so reading any repo file by ID requires a repository key. No actual decryption is attempted when this fires.","triggerScenarios":"Calling GetRepoFile(fileID) (API /api/repo/getRepoFile, used by repoFileGet) on a workspace where the repo key was never created — i.e. cloud sync / snapshots were never set up or the key was purged.","commonSituations":"Fresh workspace where snapshots were never initialized; user cleared the repo key from settings; workspace copied to another machine without importing the repo key; automated scripts hitting the repo API before any snapshot was taken.","solutions":["Set up the data repo key in Settings - About - Data repo key (or import the existing key via the key string)","If restoring on a new device, import the same repo key used by the original workspace","Create at least one snapshot (InitRepoKey happens automatically on first sync/backup) before calling repo file APIs","Check Conf.Repo.Key length client-side before invoking the API"],"exampleFix":"// before\nPOST /api/repo/getRepoFile {\"id\": \"...\"}  // no repo key configured\n// after: initialize the repo key first\nPOST /api/repo/initRepoKey   // or import key, then retry getRepoFile","handlingStrategy":"validation","validationCode":"// client-side pre-check before calling getRepoFile\nconst conf = await fetchPost(\"/api/conf/getConf\", {});\nif (!conf.data.repo.key || conf.data.repo.key.length === 0) {\n  throw new Error(\"repo key not configured; run /api/repo/initRepoKey first\");\n}","typeGuard":null,"tryCatchPattern":"data, p, err := model.GetRepoFile(fileID)\nif err != nil {\n    if err.Error() == model.Conf.Language(26) {\n        return fmt.Errorf(\"repo key not configured: %w\", err)\n    }\n    return err\n}","preventionTips":["Initialize the data repo key immediately on new workspaces","Import the same repo key on every device sharing the workspace","Avoid clearing the key in Settings - About","Check /api/conf/getConf repo.key before scripted repo API calls"],"tags":["repository","encryption","config","snapshot"],"backgroundTag":"missing-credentials","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"}