{"record":{"id":"2b4eef0a773c6a30","repo":"siyuan-note/siyuan","slug":"376-conf-language","errorCode":"376","errorMessage":"Conf.Language(376)","messagePattern":"Conf\\.Language\\(376\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/asset_download.go","lineNumber":100,"sourceCode":"// validateAssetDownloadSourceScope 在公布新的账号身份前保留未完成的资源与历史恢复来源。\nfunc validateAssetDownloadSourceScope(scope string) error {\n\texists, err := assetDownloadStateExists()\n\tif err != nil || !exists {\n\t\treturn err\n\t}\n\tif Conf.Repo == nil || len(Conf.Repo.Key) == 0 {\n\t\treturn errors.New(Conf.Language(377))\n\t}\n\tstored, err := dejavu.ReadAssetDownloadScope(assetDownloadStatePath(), Conf.Repo.Key)\n\tif err != nil || stored == scope {\n\t\treturn err\n\t}\n\treturn requireCompleteAssetDownloads()\n}\n\nfunc checkAssetDownloadAccess() error {\n\tif Conf.Sync == nil || !Conf.Sync.Enabled || Conf.GetUser() == nil {\n\t\treturn errors.New(Conf.Language(376))\n\t}\n\tswitch Conf.Sync.Provider {\n\tcase conf.ProviderSiYuan:\n\t\tif !IsSubscriber() {\n\t\t\treturn errors.New(Conf.Language(376))\n\t\t}\n\tcase conf.ProviderS3, conf.ProviderWebDAV, conf.ProviderLocal:\n\t\tif !IsPaidUser() {\n\t\t\treturn errors.New(Conf.Language(376))\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc dataRelativeAssetPath(absPath string) (string, error) {\n\tif !filepath.IsAbs(absPath) {\n\t\treturn \"\", fmt.Errorf(\"asset path must be absolute\")\n\t}","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/asset_download.go#L82-L118","documentation":"checkAssetDownloadAccess gates on-demand asset download behind sync: sync must be enabled, the user must be logged in, and per provider the account must qualify (SiYuan provider: subscriber; S3/WebDAV/Local: paid user). Failing the first gate returns i18n message 376 ('The asset has not been downloaded and cannot be retrieved right now').","triggerScenarios":"EnsureAssetLocal, EnsureAssetPrefixLocal, ensureAllSyncAssets, SetSyncAssetDownloadMode, or openRepoFileWithAssets runs while Conf.Sync is nil or disabled, or Conf.GetUser() is nil (not logged in).","commonSituations":"Cloud sync disabled in settings while a missing asset is requested; session expired so the user object is nil; automation/script tries to fetch assets offline without sync configured.","solutions":["Enable cloud sync in Settings - Sync and log in, then retry the asset access","Re-authenticate if the login session expired so Conf.GetUser() returns a user","If you do not need cloud asset download, download assets via full sync ('Download all') instead","For API-driven setups, ensure the request is made after sync is initialized rather than at boot"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const user = await fetchPost(\"/api/user/getCloudUser\", {});\nconst syncEnabled = (await fetchPost(\"/api/sync/getSyncInfo\", {})).enabled;\nif (!syncEnabled || !user?.userId) throw new Error(\"enable sync and log in before downloading assets\");","typeGuard":"const canDownloadAssets = (s, u) => Boolean(s && s.enabled && u && u.userId);","tryCatchPattern":"try {\n  await ensureAssetLocal(assetPath);\n} catch (e) {\n  if (String(e).includes(Conf.Language(376))) {\n    // surface 'enable sync / log in' UI before retrying\n  }\n}","preventionTips":["Enable cloud sync and log in before requesting on-demand asset downloads","Re-authenticate when sessions expire so the cloud user is populated","Use full 'Download all' asset mode when operating without an eligible account","Gate API scripts on sync status at startup"],"tags":["sync","assets","subscription","auth"],"backgroundTag":"feature-not-enabled","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"}