charmbracelet/crush · error
failed to decode answer question batch response: %w
Error message
failed to decode answer question batch response: %w
What it means
On a 200 response, AnswerQuestionBatch decodes the body into proto.QuestionAnswerResponse to learn whether this call resolved the question. Decode failure (empty body, HTML from a proxy, schema mismatch) yields this error, leaving the Resolved outcome unknown.
Source
Thrown at internal/client/proto.go:710
}
return resp.Resolved, nil
}
// AnswerQuestionBatch submits answers for a batch question on a
// workspace. Returns true if this call resolved the pending
// request, false if already resolved by another caller.
func (c *Client) AnswerQuestionBatch(ctx context.Context, id string, req proto.QuestionAnswer) (bool, error) {
rsp, err := c.post(ctx, fmt.Sprintf("/workspaces/%s/questions/answer", id), nil, jsonBody(req), http.Header{"Content-Type": []string{"application/json"}})
if err != nil {
return false, fmt.Errorf("failed to answer question batch: %w", err)
}
defer rsp.Body.Close()
if rsp.StatusCode != http.StatusOK {
return false, fmt.Errorf("failed to answer question batch: status code %d", rsp.StatusCode)
}
var resp proto.QuestionAnswerResponse
if err := json.NewDecoder(rsp.Body).Decode(&resp); err != nil {
return false, fmt.Errorf("failed to decode answer question batch response: %w", err)
}
return resp.Resolved, nil
}
// CancelQuestionBatch cancels the pending question batch on a
// workspace. Returns true if a question was cancelled, false if
// none was pending.
func (c *Client) CancelQuestionBatch(ctx context.Context, id string) (bool, error) {
rsp, err := c.post(ctx, fmt.Sprintf("/workspaces/%s/questions/cancel", id), nil, nil, http.Header{})
if err != nil {
return false, fmt.Errorf("failed to cancel question batch: %w", err)
}
defer rsp.Body.Close()
if rsp.StatusCode != http.StatusOK {
return false, fmt.Errorf("failed to cancel question batch: status code %d", rsp.StatusCode)
}
var resp proto.QuestionAnswerResponse
if err := json.NewDecoder(rsp.Body).Decode(&resp); err != nil {View on GitHub (pinned to 7944b8e522)
Solutions
- Capture the raw response body (curl or logging proxy) to identify the malformed payload.
- Align client and server versions so the response struct matches.
- Inspect intermediary proxies/gateways that may alter response bodies.
- Retry; if reproducible, file a server bug with a wire dump.
Defensive patterns
Strategy: retry
Type guard
func isAnswerDecodeError(err error) bool {
return err != nil && strings.Contains(err.Error(), "failed to decode answer question batch response")
} Try / catch
resolved, err := client.AnswerQuestionBatch(ctx, wsID, answer)
if isAnswerDecodeError(err) {
// outcome unknown; retry once — Resolved flag prevents double resolution
return retryAnswerBatch(ctx, wsID, answer, 1)
} Prevention
- Match client/server versions to keep response schemas aligned
- Log raw bodies when decode fails to spot proxy interference
- Retry decode failures once before giving up
- Watch for gateways returning HTML with 200 status
When it happens
Trigger: Server returns 200 with empty/malformed JSON; a proxy rewrites the body; the server's response schema differs from proto.QuestionAnswerResponse due to version skew.
Common situations: Gateway HTML interstitial with 200; partial/truncated response on flaky connections; server upgraded to a new response format while client is old.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- failed to decode cancel question batch response: %w
- failed to decode session agent info: %w
- failed to decode grant permission response: %w
- failed to decode response: %w
- failed to decode project init response: %w
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/15d1f224d2e81772.
Report an issue: GitHub.