Tencent/WeKnora · error

args must be a string or an array of strings: %w

Error message

args must be a string or an array of strings: %w

What it means

SkillExecuteTool's UnmarshalJSON wraps a json.Unmarshal failure when the raw Args payload is neither a JSON array of strings nor a JSON string. The tool accepts argv arrays (or a stringified array) and rejects any other JSON shape, wrapping the underlying json error with %w so it can be errors.Is/As inspected.

Source

Thrown at internal/agent/tools/skill_execute.go:116

		return err
	}

	i.SkillName = raw.SkillName
	i.ScriptPath = raw.ScriptPath
	i.Input = raw.Input
	i.Args = nil

	if len(raw.Args) == 0 || string(raw.Args) == "null" {
		return nil
	}

	if err := json.Unmarshal(raw.Args, &i.Args); err == nil {
		return nil
	}

	var argsString string
	if err := json.Unmarshal(raw.Args, &argsString); err != nil {
		return fmt.Errorf("args must be a string or an array of strings: %w", err)
	}

	// Some providers emit the array as a stringified JSON payload
	// (e.g. "[\"--project-name\",\"X\"]"). Treat that as an array first so the
	// model's intent is preserved; strings.Fields would otherwise split the
	// brackets/quotes into garbage tokens and the script would see nonsense argv.
	if err := json.Unmarshal([]byte(argsString), &i.Args); err == nil {
		return nil
	}

	// A plain string is interpreted as a conventional space-separated command
	// line. The tool schema continues to advertise []string, so well-formed
	// calls are unaffected; this is only a compatibility fallback for model
	// output.
	i.Args = strings.Fields(argsString)
	return nil
}

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Change the Args payload to a JSON array of strings, e.g. ["--flag","value"].
  2. If the provider only supports objects, map the object to an argv array before unmarshalling.
  3. Inspect the wrapped error with errors.As(*json.UnmarshalTypeError) to identify the offending shape.

Example fix

// before
{"tool": "skill_execute", "args": {"project-name": "X"}}
// after
{"tool": "skill_execute", "args": ["--project-name", "X"]}
Defensive patterns

Strategy: validation

Validate before calling

switch v := any(raw.Args).(type) {
case []any, string:
    // acceptable shapes
default:
    return fmt.Errorf("args must be a string or array of strings, got %T", v)
}

Type guard

func validArgsShape(raw json.RawMessage) bool {
    var arr []string
    var s string
    return json.Unmarshal(raw, &arr) == nil || json.Unmarshal(raw, &s) == nil
}

Try / catch

if err := json.Unmarshal(payload, &input); err != nil {
    var jerr *json.UnmarshalTypeError
    if errors.As(err, &jerr) && strings.Contains(err.Error(), "args must be a string or an array of strings") {
        // convert object args to argv array and retry
    }
}

Prevention

When it happens

Trigger: A provider emits Args as a JSON object (e.g. {"flag":"value"}), a number, boolean, or null, and the wrapped json.Unmarshal into []string and then into string both fail.

Common situations: Model tool-calls that pass named key/value arguments instead of an argv array; hand-written tool payloads using an unsupported shape; provider SDKs serializing arguments as objects.

Related errors


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/54ddecda2a094b07. Report an issue: GitHub.