{"record":{"id":"6f0392d328c211b6","repo":"wavetermdev/waveterm","slug":"failed-to-marshal-input-w","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_term.go","lineNumber":64,"sourceCode":"func parseTermGetScrollbackInput(input any) (*TermGetScrollbackToolInput, error) {\n\tconst (\n\t\tDefaultCount = 200\n\t\tMaxCount     = 1000\n\t)\n\n\tresult := &TermGetScrollbackToolInput{\n\t\tLineStart: 0,\n\t\tCount:     0,\n\t}\n\n\tif input == nil {\n\t\tresult.Count = DefaultCount\n\t\treturn result, nil\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.Count == 0 {\n\t\tresult.Count = DefaultCount\n\t}\n\n\tif result.Count < 0 {\n\t\treturn nil, fmt.Errorf(\"count must be positive\")\n\t}\n\n\tresult.Count = min(result.Count, MaxCount)\n\n\treturn result, nil\n}","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/aiusechat/tools_term.go#L46-L82","documentation":"parseTermGetScrollbackInput normalizes the tool's loosely-typed input (any) by round-tripping it through JSON: marshal to bytes, then unmarshal into TermGetScrollbackToolInput. This error wraps a failure of the json.Marshal step. In practice this is rare because the marshal target is the caller-provided value, but non-serializable values (channels, funcs, cyclic maps) or invalid values would trigger it.","triggerScenarios":"Calling term_get_scrollback's parse path with an input value that encoding/json cannot marshal — e.g. a map containing a channel, function, or cyclic reference instead of plain JSON-compatible data.","commonSituations":"Programmatic/preview invocations of the tool callback passing raw Go values rather than JSON-decoded tool arguments; custom tool harnesses injecting unsupported types; unsupported-type json.UnsupportedTypeError from a misbuilt input map.","solutions":["Inspect the wrapped error to identify the unsupported type (json.UnsupportedTypeError) or cycle (json.UnsupportedValueError)","Ensure tool input is plain JSON-compatible data (strings, numbers, bools, maps, slices) before invoking the parser","Build input from JSON-decoded arguments (map[string]any) as the tool framework does","If constructing input in tests/harnesses, only use marshalable values"],"exampleFix":"// before\ninput := map[string]any{\"widget_id\": \"b1\", \"count\": someFunc} // not marshalable\nparsed, err := parseTermGetScrollbackInput(input)\n// after\ninput := map[string]any{\"widget_id\": \"b1\", \"count\": 100} // JSON-compatible\nparsed, err := parseTermGetScrollbackInput(input)","handlingStrategy":"validation","validationCode":"func isJSONMarshallable(v any) error {\n    _, err := json.Marshal(v)\n    return err\n}\nif err := isJSONMarshallable(input); err != nil { return nil, err }","typeGuard":"func isPlainJSONValue(v any) bool {\n    switch v.(type) {\n    case nil, bool, string, int, int64, float64, json.Number:\n        return true\n    case map[string]any:\n        for _, e := range v.(map[string]any) { if !isPlainJSONValue(e) { return false } }\n        return true\n    case []any:\n        for _, e := range v.([]any) { if !isPlainJSONValue(e) { return false } }\n        return true\n    default:\n        return false\n    }\n}","tryCatchPattern":null,"preventionTips":["Only pass JSON-decoded tool arguments (map[string]any) into tool callbacks","Never embed channels, funcs, or cyclic structures in tool input maps","If building inputs in code, marshal them once yourself first to catch problems early"],"tags":["json","marshal","input-validation","wave"],"backgroundTag":"json-marshal-failed","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}