{"record":{"id":"dee71be5ba320225","repo":"wavetermdev/waveterm","slug":"failed-to-marshal-input-w-dee71b","errorCode":null,"errorMessage":"failed to marshal input: %w","messagePattern":"failed to marshal input: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/aiusechat/tools_web.go","lineNumber":32,"sourceCode":"\t\"github.com/wavetermdev/waveterm/pkg/wcore\"\n\t\"github.com/wavetermdev/waveterm/pkg/wstore\"\n)\n\ntype WebNavigateToolInput struct {\n\tWidgetId string `json:\"widget_id\"`\n\tUrl      string `json:\"url\"`\n}\n\nfunc parseWebNavigateInput(input any) (*WebNavigateToolInput, error) {\n\tresult := &WebNavigateToolInput{}\n\n\tif input == nil {\n\t\treturn nil, fmt.Errorf(\"input is required\")\n\t}\n\n\tinputBytes, err := json.Marshal(input)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to marshal input: %w\", err)\n\t}\n\n\tif err := json.Unmarshal(inputBytes, result); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to unmarshal input: %w\", err)\n\t}\n\n\tif result.WidgetId == \"\" {\n\t\treturn nil, fmt.Errorf(\"widget_id is required\")\n\t}\n\n\tif result.Url == \"\" {\n\t\treturn nil, fmt.Errorf(\"url is required\")\n\t}\n\n\treturn result, nil\n}\n\nfunc GetWebNavigateToolDefinition(tabId string) uctypes.ToolDefinition {","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/aiusechat/tools_web.go#L14-L50","documentation":"This error wraps a json.Marshal failure while converting the generic tool input (any) to bytes as part of re-unmarshaling it into the typed WebNavigateToolInput struct. Because the input normally originates from decoded JSON this is rare, but programmatic callers passing non-serializable values (channels, funcs, cyclic data) will hit it. The cause is preserved via %w.","triggerScenarios":"Invoking the web_navigate callback with an input any that cannot be marshaled - cyclic structures, unsupported types (func, chan), or values with failing custom marshalers.","commonSituations":"Test harnesses or programmatic tool runners passing Go-native objects with unsupported field types; plugin code injecting rich objects instead of plain maps/JSON values into tool callbacks.","solutions":["Inspect the wrapped error for the unsupported type, then pass JSON-compatible input (map[string]any or a struct with JSON tags).","Pre-marshal the input yourself to validate it before calling the callback.","Convert non-JSON types (e.g. func/chan values) to string or other serializable representations first.","If the input originates from the model, this should never fire - check for harness corruption of the arguments."],"exampleFix":"// before: callback(map[string]any{\"onReady\": func() {}}) fails with 'unsupported type: func()'; // after: callback(map[string]any{\"widget_id\": \"AB12CD34\", \"url\": \"https://example.com\"}) with JSON-safe values only","handlingStrategy":"validation","validationCode":"if _, err := json.Marshal(input); err != nil { return fmt.Errorf(\"web_navigate input not serializable: %w\", err) }","typeGuard":"func isStringMap(v any) bool { _, ok := v.(map[string]any); return ok }","tryCatchPattern":"parsed, err := parseWebNavigateInput(input); if err != nil && strings.Contains(err.Error(), \"failed to marshal input\") { /* input contained unsupported types; convert to JSON-safe map and retry */ }","preventionTips":["Pass plain map[string]any or typed structs with JSON tags as tool input.","Never embed funcs, channels, or cyclic references in tool arguments.","Round-trip inputs through JSON (ReUnmarshal) before invoking callbacks.","Add a harness-level marshal check when bridging non-JSON data into tool calls."],"tags":["json","serialization","input","web"],"backgroundTag":"json-marshal-failed","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}