charmbracelet/crush · error
questions must be an array: %w
Error message
questions must be an array: %w
What it means
The question tool accepts its questions field either as a real JSON array or as a string containing a JSON array. When the string-fallback path is taken, the trimmed string must itself parse into a question array; if json.Unmarshal into []QuestionItem fails, this error wraps the parse failure, meaning the input shape is neither a plain array nor a string-encoded array.
Source
Thrown at internal/agent/tools/question.go:51
*Alias
}{
Alias: (*Alias)(p),
}
if err := json.Unmarshal(data, aux); err != nil {
return err
}
if len(aux.Questions) == 0 {
return nil
}
// Try array first.
if err := json.Unmarshal(aux.Questions, &p.Questions); err != nil {
// Fall back to string-encoded JSON array.
var s string
if err2 := json.Unmarshal(aux.Questions, &s); err2 != nil {
return err
}
if err2 := json.Unmarshal([]byte(strings.TrimSpace(s)), &p.Questions); err2 != nil {
return fmt.Errorf("questions must be an array: %w", err2)
}
}
return nil
}
// QuestionItem is a single question from the tool input.
type QuestionItem struct {
Label string `json:"label,omitempty" description:"Short tab header label (3 words max)."`
Type string `json:"type" description:"The type of question: yes_no, single_choice, multi_choice, or free_text"`
Question string `json:"question" description:"The question text"`
Description string `json:"description" description:"Required markdown description shown below the question"`
Choices []QuestionChoice `json:"choices,omitempty" description:"List of choices"`
Options []QuestionChoice `json:"options,omitempty"` // alias for Choices
}
// GetChoices returns choices, preferring the Choices field over Options.
func (q QuestionItem) GetChoices() []QuestionChoice {
if len(q.Choices) > 0 {View on GitHub (pinned to 7944b8e522)
Solutions
- Send questions as a proper JSON array of question objects, not a string
- If double-encoded, decode the string once and confirm it is valid JSON array syntax
- Log the raw aux.Questions value to see the exact malformed payload
- Upgrade/fix the client or prompt that produces stringified arguments
Example fix
// before
{"questions": "[{question: 'title?'}]"} // invalid inner JSON
// after
{"questions": [{"question": "title?", "options": ["a","b"]}]} Defensive patterns
Strategy: validation
Validate before calling
switch v := raw.(type) {
case []any:
// ok: already an array
case string:
var check []any
if err := json.Unmarshal([]byte(strings.TrimSpace(v)), &check); err != nil {
return fmt.Errorf("questions is not a JSON array: %w", err)
}
default:
return fmt.Errorf("questions must be array or string-encoded array")
} Type guard
func isQuestionArray(raw json.RawMessage) bool {
var arr []QuestionItem
return json.Unmarshal(raw, &arr) == nil
} Try / catch
if err := json.Unmarshal(data, ¶ms); err != nil {
var syn *json.SyntaxError
if errors.As(err, &syn) {
// log syn.Offset to locate malformed inner JSON
}
} Prevention
- Emit questions as a native JSON array in tool arguments
- Avoid double-encoding arrays as strings
- Log raw tool arguments when Unmarshal fails
- Pin the client/model version that serializes arguments correctly
When it happens
Trigger: Client sends questions as a string whose content is not a valid JSON array (e.g. plain prose, single-quoted pseudo-JSON, or a JSON object) — or the field is some other type that failed the primary array decode.
Common situations: Models emitting double-encoded or malformed JSON in tool arguments; middleware re-serializing arguments to strings; hand-written test payloads with unquoted JSON.
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
- failed to unmarshal provider data: %w
- unmarshal response: %w: %s
- failed to decode response: %w
- error parsing parameters: %s
- old_string cannot be empty for content replacement
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/8db9658a683fb06f.
Report an issue: GitHub.