siyuan-note/siyuan · error
invalid tool arguments: %w
Error message
invalid tool arguments: %w
What it means
The JSON payload sent as a tool's `arguments` could not be unmarshalled into `map[string]any`. This is the raw transport-level parse failure, distinct from the schema validation that runs next (`ValidateInputContext`) — it means the bytes themselves are not valid JSON or do not decode into a JSON object.
Source
Thrown at kernel/mcp/server.go:265
Title: tool.Title,
Description: tool.Description,
InputSchema: tool.InputSchema,
}
if tool.OutputSchema != nil {
sdkTool.OutputSchema = tool.OutputSchema
}
if tool.ReadOnlyHint {
sdkTool.Annotations = &mcpsdk.ToolAnnotations{ReadOnlyHint: true}
}
server.AddTool(sdkTool, func(ctx context.Context, request *mcpsdk.CallToolRequest) (*mcpsdk.CallToolResult, error) {
if allowed != nil && !allowed() {
return toolErrorResult("MCP capability is disabled or no longer available"), nil
}
arguments := map[string]any{}
if len(request.Params.Arguments) > 0 {
if err := json.Unmarshal(request.Params.Arguments, &arguments); err != nil {
return nil, fmt.Errorf("invalid tool arguments: %w", err)
}
}
if arguments == nil {
arguments = map[string]any{}
}
if err := validator.ValidateInputContext(ctx, arguments); err != nil {
return toolErrorResult(fmt.Sprintf("invalid tool arguments: %v", err)), nil
}
releaseBoxLeases := func() {}
if tool.BoxLeaseResolver != nil {
leaseContext, contextErr := requestOperationContext(ctx, request)
if contextErr != nil {
logging.LogWarnf("mcp: acquire request operation scope for tool [%s] failed: %v", name, contextErr)
return toolErrorResult(contextErr.Error()), nil
}
releaseBoxLeases, err = model.AcquireEncryptedBoxOperations(leaseContext, tool.BoxLeaseResolver(arguments))
if err != nil {
if errors.Is(err, model.ErrEncryptedBoxNotUnlocked) {View on GitHub (pinned to 251596fc0d)
Solutions
- Ensure the `arguments` field is a JSON object (`{...}`), not an array or scalar.
- Validate the request JSON with a linter/validator before sending; fix any syntax errors flagged.
- If arguments arrive pre-stringified, decode them once on the client before transmission.
Example fix
// before (arguments sent as array)
{"method":"tools/call","params":{"name":"block_move","arguments":["20240101000000-abc"]}}
// after (object keyed by parameter name)
{"method":"tools/call","params":{"name":"block_move","arguments":{"id":"20240101000000-abc","parentID":"20240101000000-def"}}} Defensive patterns
Strategy: validation
Validate before calling
// Client-side: ensure arguments is a JSON object before sending.
function buildCall(name, args) {
if (args == null || typeof args !== "object" || Array.isArray(args)) {
throw new Error("arguments must be a JSON object")
}
return JSON.stringify({ method: "tools/call", params: { name, arguments: args } })
} Type guard
// Narrow arguments to a record before invoking the tool.
function isArgumentsObject(v): v is Record<string, unknown> {
return v != null && typeof v === "object" && !Array.isArray(v)
} Prevention
- Send arguments as a JSON object keyed by parameter name.
- Validate JSON syntax with a linter before transmission.
- Do not double-serialize arguments into a string.
When it happens
Trigger: An MCP `tools/call` request whose `params.arguments` is a JSON array, a bare string/number, or syntactically broken JSON (trailing comma, unescaped quote). The SDK handler at `server.go:264` runs `json.Unmarshal(request.Params.Arguments, &arguments)` and it returns an error.
Common situations: The MCP client sends arguments as an array instead of an object. A hand-crafted JSON-RPC request with malformed JSON. A serialization mismatch where the client encodes arguments twice (double-escaped JSON string).
Related errors
- name must end in .html or .htm
- empty result
- path is required
- path escapes templates dir: %s
- JSON depth exceeds %d
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/df7d54d762e359db.
Report an issue: GitHub.