{"record":{"id":"58407e760b0d1210","repo":"siyuan-note/siyuan","slug":"tool-arguments-must-be-a-json-object","errorCode":null,"errorMessage":"tool arguments must be a JSON object","messagePattern":"tool arguments must be a JSON object","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/agent/tools.go","lineNumber":345,"sourceCode":"\t\tif data, err := json.Marshal(result.StructuredContent); err == nil {\n\t\t\treturn string(data)\n\t\t}\n\t}\n\treturn \"(empty result)\"\n}\n\n// parseToolArgs 在流结束后解析完整的工具参数，避免把损坏的 JSON 误报为缺少 schema 字段。\nfunc parseToolArgs(argsJSON string) (map[string]any, error) {\n\tif strings.TrimSpace(argsJSON) == \"\" {\n\t\treturn map[string]any{}, nil\n\t}\n\n\tvar args map[string]any\n\tif err := json.Unmarshal([]byte(argsJSON), &args); err != nil {\n\t\treturn nil, fmt.Errorf(\"tool arguments are not valid JSON: %w\", err)\n\t}\n\tif args == nil {\n\t\treturn nil, fmt.Errorf(\"tool arguments must be a JSON object\")\n\t}\n\treturn args, nil\n}\n","sourceCodeStart":327,"sourceCodeEnd":349,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/agent/tools.go#L327-L349","documentation":"After a successful json.Unmarshal, parseToolArgs checks that the result is a non-nil map. JSON text like `null` or `\"string\"` unmarshals without error into a nil map (or fails type conversion), so this error rejects arguments that are valid JSON but not a JSON object. Tool arguments must be a key/value object for the capability executor to look up parameters.","triggerScenarios":"Calling parseToolArgs with argsJSON equal to `null`, or any JSON scalar/array that unmarshals into a nil map[string]any (e.g. arrays actually fail unmarshal into map, but `null` succeeds with nil). The classic trigger is a model emitting `null` as the arguments field.","commonSituations":"An LLM fills in `null` for arguments when a tool takes no parameters; a caller passes an already-decoded nil map serialized back to string; a test fixture uses `null` as arguments.","solutions":["Ensure the tool-call arguments field is serialized as a JSON object `{...}`, even when empty: `{}` instead of `null`.","For no-parameter tools, have callers pass `{}` explicitly; parseToolArgs also returns an empty map for empty strings.","Sanitize upstream input: if argsJSON == \"null\" (after trim), replace with \"{}\" before parsing if the tool tolerates empty args."],"exampleFix":"// before\nparseToolArgs(\"null\") // error: must be a JSON object\n\n// after\nif strings.TrimSpace(argsJSON) == \"null\" {\n    argsJSON = \"{}\"\n}\nparsed, err := parseToolArgs(argsJSON)","handlingStrategy":"validation","validationCode":"function ensureObjectArgs(s) {\n  const t = (s ?? \"\").trim();\n  if (t === \"\" || t === \"null\") return \"{}\";\n  const v = JSON.parse(t);\n  if (typeof v !== \"object\" || v === null || Array.isArray(v)) throw new Error(\"tool arguments must be a JSON object\");\n  return t;\n}","typeGuard":"func isJSONObjectArgs(raw string) bool {\n    var m map[string]any\n    return json.Unmarshal([]byte(raw), &m) == nil && m != nil\n}","tryCatchPattern":"args, err := parseToolArgs(raw)\nif err != nil {\n    if err.Error() == \"tool arguments must be a JSON object\" {\n        args = map[string]any{} // degrade to empty args if the tool has no required params\n    }\n}","preventionTips":["Serialize no-argument tool calls as {} not null","Always keep tool schemas declaring type: object","Normalize null arguments to {} before calling the kernel"],"tags":["json","llm-tools","validation"],"backgroundTag":"schema-validation-failed","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"}