{"record":{"id":"17b779faa1b5999e","repo":"siyuan-note/siyuan","slug":"invalid-config-s-v","errorCode":null,"errorMessage":"invalid config.%s: %v","messagePattern":"invalid config\\.(.+?): (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/plugin/api_agent.go","lineNumber":305,"sourceCode":"\tactionEffects := map[string]tools.ToolEffects{}\n\tif err := unmarshalCapabilityJSON(rt, value, &actionEffects, \"actionEffects\"); err != nil {\n\t\treturn nil, err\n\t}\n\tfor action := range actionEffects {\n\t\tif strings.TrimSpace(action) == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"config.actionEffects contains an empty action\")\n\t\t}\n\t}\n\treturn actionEffects, nil\n}\n\nfunc unmarshalCapabilityJSON(rt *goja.Runtime, value goja.Value, target any, field string) error {\n\tjsonValue, err := value.ToObject(rt).MarshalJSON()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to serialize config.%s: %v\", field, err)\n\t}\n\tif err = json.Unmarshal(jsonValue, target); err != nil {\n\t\treturn fmt.Errorf(\"invalid config.%s: %v\", field, err)\n\t}\n\treturn nil\n}\n","sourceCodeStart":287,"sourceCodeEnd":309,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/plugin/api_agent.go#L287-L309","documentation":"unmarshalCapabilityJSON decodes the serialized JSON of a named config field into its Go target struct. If json.Unmarshal fails (the JSON does not fit the target's types), this error is returned with the field name. The value serializes fine but has the wrong shape or types for the capability config.","triggerScenarios":"config.effects or config.actionEffects has wrong-typed members, e.g. effects: {run: \"readonly\"} instead of an effects object, or actionEffects values missing expected fields / with wrong types like numeric hints.","commonSituations":"Authors guess the config shape instead of following the ToolEffects struct; using string flags where booleans are expected; nesting the map one level too deep or shallow.","solutions":["Match the documented ToolEffects shape: e.g. { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }","Use boolean values for hint fields, not strings or numbers","Read the wrapped invalid config.<field> message to see the exact decode failure","Compare against a working plugin sample's config"],"exampleFix":"// before\nconfig.effects = { run: \"readonly\" }\n\n// after\nconfig.effects = { run: { readOnlyHint: true, destructiveHint: false } }","handlingStrategy":"validation","validationCode":"function validateEffects(effects) {\n  return Object.entries(effects || {}).every(([k, v]) =>\n    k && typeof v === \"object\" && v !== null &&\n    Object.values(v).every((x) => typeof x === \"boolean\"));\n}","typeGuard":"const isToolEffects = (v) => v !== null && typeof v === \"object\" && !Array.isArray(v) && Object.values(v).every((x) => typeof x === \"boolean\");","tryCatchPattern":"try {\n  registerCapability(config);\n} catch (e) {\n  if (String(e).includes(\"invalid config.\")) {\n    console.error(\"Capability config shape/type mismatch\", e);\n  }\n}","preventionTips":["Copy the ToolEffects shape from the official sample plugin","Use booleans for all hint fields","Round-trip check: JSON.parse(JSON.stringify(config)) should keep the same shape"],"tags":["plugin","json","config","type-mismatch"],"backgroundTag":"config-type-mismatch","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"}