wavetermdev/waveterm · error
failed to unmarshal input: %w
Error message
failed to unmarshal input: %w
What it means
This wraps the json.Unmarshal half of the marshal/unmarshal round-trip in parseTermGetScrollbackInput, which re-decodes the marshaled input into *TermGetScrollbackToolInput. It fires when the input's shape does not match the struct's expected JSON types — most commonly when the AI model passes wrong types (e.g. count as a string "200" or widget_id as a number) so unmarshal fails with a json.UnmarshalTypeError.
Source
Thrown at pkg/aiusechat/tools_term.go:68
)
result := &TermGetScrollbackToolInput{
LineStart: 0,
Count: 0,
}
if input == nil {
result.Count = DefaultCount
return result, nil
}
inputBytes, err := json.Marshal(input)
if err != nil {
return nil, fmt.Errorf("failed to marshal input: %w", err)
}
if err := json.Unmarshal(inputBytes, result); err != nil {
return nil, fmt.Errorf("failed to unmarshal input: %w", err)
}
if result.Count == 0 {
result.Count = DefaultCount
}
if result.Count < 0 {
return nil, fmt.Errorf("count must be positive")
}
result.Count = min(result.Count, MaxCount)
return result, nil
}
func getTermScrollbackOutput(tabId string, widgetId string, rpcData wshrpc.CommandTermGetScrollbackLinesData) (*TermGetScrollbackToolOutput, error) {
ctx, cancelFn := context.WithTimeout(context.Background(), 5*time.Second)
defer cancelFn()View on GitHub (pinned to a4447c1563)
Solutions
- Read the wrapped *json.UnmarshalTypeError to see which field/type mismatched
- Coerce common LLM type slips before parsing: accept numeric strings for count/line_start and stringify numeric widget_id
- Re-prompt or return a schema reminder so the model emits widget_id as string and count/line_start as integers
- Validate the input map's types manually before the round-trip if inputs are untrusted
Example fix
// before
if err := json.Unmarshal(inputBytes, result); err != nil {
return nil, fmt.Errorf("failed to unmarshal input: %w", err)
}
// after
if err := json.Unmarshal(inputBytes, result); err != nil {
var typeErr *json.UnmarshalTypeError
if errors.As(err, &typeErr) {
return nil, fmt.Errorf("field %q has wrong type (expected %s): %w", typeErr.Field, typeErr.Type, err)
}
return nil, fmt.Errorf("failed to unmarshal input: %w", err)
} Defensive patterns
Strategy: type-guard
Validate before calling
func validateScrollbackInput(m map[string]any) error {
if v, ok := m["widget_id"]; ok { if _, ok := v.(string); !ok { return fmt.Errorf("widget_id must be a string") } }
for _, k := range []string{"count", "line_start"} {
if v, ok := m[k]; ok {
switch n := v.(type) {
case float64:
if n != float64(int(n)) { return fmt.Errorf("%s must be an integer", k) }
case string:
if _, err := strconv.Atoi(n); err != nil { return fmt.Errorf("%s must be an integer", k) }
default:
return fmt.Errorf("%s must be an integer", k)
}
}
}
return nil
} Type guard
func asInt(v any) (int, bool) {
switch n := v.(type) {
case float64: return int(n), true
case json.Number: i, err := n.Int64(); return int(i), err == nil
case string: i, err := strconv.Atoi(n); return i, err == nil
}
return 0, false
} Try / catch
parsed, err := parseTermGetScrollbackInput(input)
if err != nil {
var typeErr *json.UnmarshalTypeError
if errors.As(err, &typeErr) {
return nil, fmt.Errorf("bad tool argument %q: expected %s", typeErr.Field, typeErr.Type)
}
return nil, err
} Prevention
- Mark the tool Strict: true (like capture_screenshot) so the model's arguments are schema-validated
- Coerce numeric strings to ints before the round-trip for LLM robustness
- Include explicit type descriptions in InputSchema and re-prompt on type errors
When it happens
Trigger: term_get_scrollback invoked with input whose field types conflict with TermGetScrollbackToolInput: count or line_start as a non-integer (string, float with fraction, bool), or widget_id as a non-string (number, object, array).
Common situations: LLM emits tool arguments with wrong JSON types (count: "200", widget_id: 12345); upstream harness passes a JSON array or scalar instead of an object; schema not enforced (this tool is not Strict, so malformed arguments can reach the parser).
Related errors
- invalid input format: %w
- invalid input format: %w
- failed to marshal input: %w
- count must be positive
- failed to unmarshal response: %w
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/bdabcb2dcb2f0b96.
Report an issue: GitHub.