charmbracelet/crush · error

failed to answer question batch: %w

Error message

failed to answer question batch: %w

What it means

AnswerQuestionBatch POSTs answers to /workspaces/{id}/questions/answer. This error wraps any transport-level failure from c.post — connection refused, DNS failure, TLS error, or context cancellation — meaning the answers were never delivered. The pending question may still be unresolved.

Source

Thrown at internal/client/proto.go:702

	}
	defer rsp.Body.Close()
	if rsp.StatusCode != http.StatusOK {
		return false, fmt.Errorf("failed to grant permission: status code %d", rsp.StatusCode)
	}
	var resp proto.PermissionGrantResponse
	if err := json.NewDecoder(rsp.Body).Decode(&resp); err != nil {
		return false, fmt.Errorf("failed to decode grant permission response: %w", err)
	}
	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 {

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Confirm server connectivity and retry AnswerQuestionBatch; the response's Resolved flag reports whether this call or another caller resolved the question.
  2. Check the client base URL/port configuration.
  3. Increase the context timeout if answers time out on large batches.
  4. Handle a false Resolved return gracefully — another subscriber may have answered first, which is not an error.

Example fix

// before
resolved, err := client.AnswerQuestionBatch(ctx, wsID, answer)
if err != nil { return err }
// after
resolved, err := client.AnswerQuestionBatch(ctx, wsID, answer)
if err != nil {
	// safe to retry: answering is idempotent via Resolved flag
	return fmt.Errorf("answering question batch on %s: %w", wsID, err)
}
if !resolved { log.Info("question already resolved by another caller") }
Defensive patterns

Strategy: retry

Validate before calling

// Ensure the server is reachable and answers are well-formed before sending
if serverReachable(ctx, baseURL) != nil {
	return errors.New("cannot answer questions: server unreachable")
}

Try / catch

resolved, err := client.AnswerQuestionBatch(ctx, wsID, answer)
if err != nil {
	if errors.Is(err, context.DeadlineExceeded) { return err }
	return retryAnswerBatch(ctx, wsID, answer, 3) // idempotent via Resolved flag
}
if !resolved { log.Info("question already resolved elsewhere") }

Prevention

When it happens

Trigger: Calling AnswerQuestionBatch when the server is down or unreachable, the network drops mid-request, or the caller's context deadline expires before the POST finishes.

Common situations: Server restart between question receipt and answer; user answering on a flaky connection; long-running workspace where the context times out; wrong host/port configuration.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29). Data as JSON: /api/errors/1affc426886826ae. Report an issue: GitHub.