{"record":{"id":"d9f62832d28146cc","repo":"siyuan-note/siyuan","slug":"conf-language-314-d9f628","errorCode":null,"errorMessage":"Conf.Language(314)","messagePattern":"Conf\\.Language\\(314\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/asset_download.go","lineNumber":385,"sourceCode":"}\n\n// readRepoFileWithAssets 将仓库实例的创建和历史分块补齐纳入来源读锁。\nfunc readRepoFileWithAssets(fileID string) ([]byte, *entity.File, error) {\n\tassetDownloadSourceMu.RLock()\n\tdefer assetDownloadSourceMu.RUnlock()\n\tif Conf.Repo == nil || len(Conf.Repo.Key) == 0 {\n\t\treturn nil, nil, errors.New(Conf.Language(26))\n\t}\n\trepo, err := newRepositoryWithAssetSourceLocked()\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tfile, err := repo.GetFile(fileID)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tif boxID := encryptedBoxIDFromRepoPath(file.Path); boxID != \"\" && !IsBoxUnlocked(boxID) {\n\t\treturn nil, nil, errors.New(Conf.Language(314))\n\t}\n\tdata, err := openRepoFileWithAssets(repo, file)\n\treturn data, file, err\n}\n\nfunc ensureRepoSnapshotComplete(repo *dejavu.Repo, indexID string) error {\n\tindex, err := repo.GetIndex(indexID)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn repo.GetFilesIter(index, func(file *entity.File) error {\n\t\tif !repoFileNeedsDownload(file) {\n\t\t\treturn nil\n\t\t}\n\t\tif err := checkAssetDownloadAccess(); err != nil {\n\t\t\treturn err\n\t\t}\n\t\thandleCloudError := cloudRepoErrorHandler()","sourceCodeStart":367,"sourceCodeEnd":403,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/asset_download.go#L367-L403","documentation":"After locating the repo file, readRepoFileWithAssets checks whether the file belongs to an encrypted notebook (encryptedBoxIDFromRepoPath) and, if that box is not currently unlocked, returns the localized message Conf.Language(314) ('encrypted notebook is locked' family). Encrypted notebooks keep their content ciphertext on disk; reading repo snapshots of their files is blocked until the user supplies the passphrase.","triggerScenarios":"GetRepoFile / RollbackRepoSnapshotFile / OpenRepoSnapshotFile / ExportRepoFile targeting a file whose path maps to an encrypted box, executed while the box is in locked state (after app start, after auto-lock, or before entering the password).","commonSituations":"User opens snapshot history for a doc inside an encrypted notebook that auto-locked after inactivity; a script or plugin reads repo files at startup before any box unlock; exporting a repo snapshot file from a locked encrypted notebook.","solutions":["Unlock the encrypted notebook in the UI (enter its passphrase) and retry the operation","Call the box unlock API (e.g. UnlockBox with the password) programmatically before the read","Check IsBoxUnlocked(boxID) first and surface a 'please unlock the notebook' message instead of calling the API","If the passphrase is forgotten, restore content from a device where the box is unlocked or from backups"],"exampleFix":"// before\ndata, err := model.GetRepoFile(fileID) // notebook locked\n// after\nif boxLocked {\n    if err := model.UnlockBox(boxID, password); err != nil { return err }\n}\ndata, err := model.GetRepoFile(fileID)","handlingStrategy":"validation","validationCode":"if model.IsEncryptedBox(boxID) && !model.IsBoxUnlocked(boxID) {\n    return errors.New(\"unlock the encrypted notebook before reading repo files\")\n}","typeGuard":null,"tryCatchPattern":"data, err := model.GetRepoFile(fileID)\nif err != nil && strings.Contains(err.Error(), conf.Conf.Language(314)) {\n    util.PushMsg(\"please unlock the encrypted notebook\", 5000)\n    return err\n}","preventionTips":["Check IsBoxUnlocked before any repo-file API on encrypted boxes","Avoid scripts touching encrypted boxes at startup before unlock","Set an auto-lock interval compatible with your workflow","Surface the localized 314 message to users instead of raw errors"],"tags":["encryption","locked-notebook","access-control"],"backgroundTag":"authentication-required","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}