siyuan-note/siyuan · error
invalid tool arguments
Error message
invalid tool arguments: %w
What it means
The MCP tools/call handler parses request.Params.Arguments as a JSON object of named arguments. If the raw JSON bytes are malformed (not valid JSON), the handler fails fast with 'invalid tool arguments' wrapping the json.Unmarshal error instead of invoking the tool.
Solutions
- Validate the arguments payload is well-formed JSON (json.Valid) before sending the tools/call request
- Ensure arguments serialize as a JSON object with string keys via a proper JSON marshaller
- Check intermediaries for body truncation or re-encoding
- Inspect the wrapped %w cause in the error for the exact JSON offset of the syntax problem
Example fix
// before
args := "{name: 'x'}" // invalid JSON
// after
args, _ := json.Marshal(map[string]any{"name": "x"}) Defensive patterns
Strategy: validation
Validate before calling
if !json.Valid([]byte(argsJSON)) {
return fmt.Errorf("arguments are not valid JSON")
}
var probe map[string]any
if err := json.Unmarshal([]byte(argsJSON), &probe); err != nil {
return fmt.Errorf("arguments must be a JSON object: %w", err)
} Try / catch
result, err := client.CallTool(ctx, req)
if err != nil && strings.Contains(err.Error(), "invalid tool arguments") {
// fix and re-serialize arguments before retrying
} Prevention
- Always serialize arguments with a JSON encoder, never string concatenation
- Round-trip arguments through json.Marshal before sending in tests
- Beware double-encoded JSON strings ("{\"a\":1}" as a string) at proxies
When it happens
Trigger: An MCP client sends a tools/call whose params.arguments bytes are invalid JSON — e.g. truncated payload, single quotes instead of JSON quotes, or a JSON array/string instead of an object-shaped raw body (unmarshal into map[string]any fails for non-object types).
Common situations: Hand-written MCP clients or curl tests with improperly escaped arguments; a serialization bug in a plugin or SDK producing malformed JSON; proxy/middleware truncating the request body.
Understand the failure class
Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.
Related errors
- JSON depth exceeds
- JSON node count exceeds
- attr must be a string or null (got %T)
- builtin color must not be null
- builtin style must not be null
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/df7d54d762e359db.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/mcp/server.go:266
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 9f775e8a12)