wavetermdev/waveterm · error

failed to unmarshal input: %w

Error message

failed to unmarshal input: %w

What it means

This error wraps a json.Unmarshal failure when the (re-marshaled) input bytes cannot be decoded into WebNavigateToolInput{WidgetId, Url string}. It fires when fields have the wrong JSON types - e.g. widget_id given as a number or url as an object - because Unmarshal is strict about string fields. The underlying type error is preserved via %w.

Source

Thrown at pkg/aiusechat/tools_web.go:36

type WebNavigateToolInput struct {
	WidgetId string `json:"widget_id"`
	Url      string `json:"url"`
}

func parseWebNavigateInput(input any) (*WebNavigateToolInput, error) {
	result := &WebNavigateToolInput{}

	if input == nil {
		return nil, fmt.Errorf("input is required")
	}

	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.WidgetId == "" {
		return nil, fmt.Errorf("widget_id is required")
	}

	if result.Url == "" {
		return nil, fmt.Errorf("url is required")
	}

	return result, nil
}

func GetWebNavigateToolDefinition(tabId string) uctypes.ToolDefinition {

	return uctypes.ToolDefinition{
		Name:        "web_navigate",
		DisplayName: "Navigate Web Widget",

View on GitHub (pinned to a4447c1563)

Solutions

  1. Read the wrapped error to see which field has the wrong type, then correct the tool call so widget_id and url are plain strings.
  2. Re-enable or tighten the tool's InputSchema (type: string for both fields, additionalProperties: false) so the model cannot emit wrong-typed values.
  3. In the caller, coerce/validate types before invoking (e.g. convert numeric ids to their 8-character string form).
  4. If passing a struct programmatically, confirm its JSON tags produce {"widget_id": ..., "url": ...}.
  5. Return the specific *json.UnmarshalTypeError field info back to the model so it can self-correct.

Example fix

// before: callback(map[string]any{"widget_id": 12345, "url": "https://example.com"}) fails with 'cannot unmarshal number into Go struct field .widget_id of type string'; // after: callback(map[string]any{"widget_id": "AB12CD34", "url": "https://example.com"})
Defensive patterns

Strategy: type-guard

Validate before calling

m, ok := input.(map[string]any); if !ok { return errors.New("web_navigate input must be an object") }; if _, ok := m["widget_id"].(string); !ok { return errors.New("widget_id must be a string") }; if _, ok := m["url"].(string); !ok { return errors.New("url must be a string") }

Type guard

func validWebNavigateInput(input any) bool { m, ok := input.(map[string]any); if !ok { return false }; w, okW := m["widget_id"].(string); u, okU := m["url"].(string); return okW && okU && w != "" && u != "" }

Try / catch

parsed, err := parseWebNavigateInput(input); if err != nil { var typeErr *json.UnmarshalTypeError; if errors.As(err, &typeErr) { return nil, fmt.Errorf("field %s has wrong type: %w", typeErr.Field, err) } }

Prevention

When it happens

Trigger: The web_navigate tool receives input where widget_id or url is not a JSON string (number, bool, array, object) or where the input is valid JSON but of an incompatible shape (e.g. a bare string or array instead of an object).

Common situations: LLM emits widget_id as a numeric id or nests the fields (input: {"widget_id": {"id": "..."}}); harness passes a pre-typed struct that marshals to a different shape; schema enforcement disabled so malformed arguments reach the callback.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/4f1af33d4a6cfcd5. Report an issue: GitHub.