{"record":{"id":"8a4ad13c2b02b593","repo":"siyuan-note/siyuan","slug":"plugin-publish-data-has-not-been-generated","errorCode":null,"errorMessage":"plugin publish data has not been generated","messagePattern":"plugin publish data has not been generated","errorType":"exception","errorClass":"ErrPluginPublishMissing","httpStatus":null,"severity":"info","filePath":"kernel/model/plugin_publish.go","lineNumber":22,"sourceCode":"\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/88250/gulu\"\n\t\"github.com/gin-gonic/gin\"\n\t\"github.com/siyuan-note/siyuan/kernel/bazaar\"\n\t\"github.com/siyuan-note/siyuan/kernel/util\"\n)\n\nvar (\n\tErrPluginPublishDenied  = errors.New(\"plugin publish access denied\")\n\tErrPluginPublishMissing = errors.New(\"plugin publish data has not been generated\")\n\tErrPluginPublishInvalid = errors.New(\"invalid plugin publish declaration or data\")\n\tpluginPublishLock       sync.Mutex\n)\n\n// PluginPublishDeclaration 的资源为精确文件名，数据为可公开的顶层标量字段，不支持目录或通配符。\ntype PluginPublishDeclaration struct {\n\tResources []string `json:\"resources\"`\n\tData      []string `json:\"data\"`\n}\n\ntype PluginPublishInfo struct {\n\tResources []string `json:\"resources\"`\n\tFields    []string `json:\"fields\"`\n\tGranted   bool     `json:\"granted\"`\n}\n\ntype pluginPublishState struct {\n\tVersion int                        `json:\"version\"`","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/plugin_publish.go#L4-L40","documentation":"ErrPluginPublishMissing indicates the plugin publish data state exists (authorization may be fine) but its data map is nil — i.e. no publish data has been generated/saved yet for this plugin. LoadPluginPublishData raises it before reading fields. The API layer maps it to HTTP 404 Not Found.","triggerScenarios":"LoadPluginPublishData(name) when the reconciled pluginPublishState has Data == nil — typically the very first read before any SetPluginPublishData/save call; TestPluginPublishDataLifecycle exercises the fresh-install case.","commonSituations":"Calling the publish data API for a freshly installed plugin before the plugin ever persisted its publish data; the state file was recreated after plugin reinstall; a plugin upgrade reset the data map while authorization persisted.","solutions":["Call the publish-data save endpoint (SavePluginPublishData / SetPluginPublishData...) once to initialize the data map before loading","Treat 404 as 'initialize needed' in the client and fall back to an empty object","Check that plugins/<name>/publish state file exists under the workspace and was not deleted"],"exampleFix":"// before\ndata, err := model.LoadPluginPublishData(name)\n// after\nif errors.Is(err, model.ErrPluginPublishMissing) {\n    data = map[string]json.RawMessage{} // first read before any data saved\n} else if err != nil {\n    return err\n}","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  data = await fetchPost(\"/api/publish/loadPluginPublishData\", {name});\n} catch (e) {\n  if (e.code === 404) data = {}; // not generated yet\n  else throw e;\n}","preventionTips":["Save publish data once during plugin first-run/initialization so the data map exists","Treat 404 on load as an empty-state, not a hard failure","After plugin reinstall, re-save publish data since state may be reset"],"tags":["publish","plugin","not-found","state"],"backgroundTag":"resource-not-found","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"}