charmbracelet/crush · error
failed to decode init prompt response: %w
Error message
failed to decode init prompt response: %w
What it means
After a 200 response, GetInitializePrompt decodes the body expecting {"prompt": string}. Any decode failure (empty body, non-JSON, wrong shape) raises this error. It signals a server/client response-contract mismatch, not a connectivity issue, and propagates to InitializePrompt.
Source
Thrown at internal/client/config.go:214
return nil
}
// GetInitializePrompt retrieves the initialization prompt from the
// server.
func (c *Client) GetInitializePrompt(ctx context.Context, id string) (string, error) {
rsp, err := c.get(ctx, fmt.Sprintf("/workspaces/%s/project/init-prompt", id), nil, nil)
if err != nil {
return "", fmt.Errorf("failed to get init prompt: %w", err)
}
defer rsp.Body.Close()
if rsp.StatusCode != http.StatusOK {
return "", fmt.Errorf("failed to get init prompt: status code %d", rsp.StatusCode)
}
var result struct {
Prompt string `json:"prompt"`
}
if err := json.NewDecoder(rsp.Body).Decode(&result); err != nil {
return "", fmt.Errorf("failed to decode init prompt response: %w", err)
}
return result.Prompt, nil
}
// ListSkills retrieves the visible skills for a workspace.
func (c *Client) ListSkills(ctx context.Context, id string) ([]proto.SkillInfo, error) {
rsp, err := c.get(ctx, fmt.Sprintf("/workspaces/%s/skills", id), nil, nil)
if err != nil {
return nil, fmt.Errorf("failed to list skills: %w", err)
}
defer rsp.Body.Close()
if rsp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("failed to list skills: status code %d", rsp.StatusCode)
}
var skills []proto.SkillInfo
if err := json.NewDecoder(rsp.Body).Decode(&skills); err != nil {
return nil, fmt.Errorf("failed to decode skills: %w", err)
}View on GitHub (pinned to 7944b8e522)
Solutions
- Log or capture the raw response body to see the actual payload
- Align client and server versions for the init-prompt contract
- Reconfigure or bypass proxies/SSO walls that return HTML with 200
- Add a server-side guard so internal errors never return 200 with a non-JSON body
Example fix
// before
prompt, err := client.GetInitializePrompt(ctx, id)
if err != nil {
return err
}
// after
prompt, err := client.GetInitializePrompt(ctx, id)
if err != nil {
log.Printf("init-prompt decode failed; check server version/proxy: %v", err)
return err
} Defensive patterns
Strategy: type-guard
Validate before calling
// Verify the endpoint returns JSON before decoding
testResp, err := http.Get(client.BaseURL() + "/healthz")
if err != nil {
return err
}
ct := testResp.Header.Get("Content-Type")
testResp.Body.Close()
if !strings.HasPrefix(ct, "application/json") {
return fmt.Errorf("non-JSON API responses detected (proxy/auth wall?)")
} Type guard
func looksLikeJSON(b []byte) bool {
t := bytes.TrimSpace(b)
return len(t) > 0 && (t[0] == '{' || t[0] == '[')
} Try / catch
prompt, err := c.GetInitializePrompt(ctx, id)
if err != nil {
if strings.Contains(err.Error(), "failed to decode") {
// contract mismatch: fall back to a local default prompt
return defaultInitPrompt, nil
}
return err
} Prevention
- Golden-test the init-prompt response payload on the server side
- Keep client and server releases in lockstep when the payload schema changes
- Detect and reject HTML/auth-wall responses at the proxy layer
- Ship a local fallback prompt so onboarding survives contract drift
When it happens
Trigger: Calling GetInitializePrompt when the 200 body is not decodable into {prompt: string}: empty body, HTML injected by a proxy or auth wall, or a server version returning a renamed/nested prompt field.
Common situations: Client/server version skew after the init-prompt payload changed; reverse proxy or SSO login page returned instead of JSON; compression middleware misconfiguration; server returning 200 with an empty body on internal errors.
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 project init response: %w
- failed to decode session agent info: %w
- failed to decode grant permission response: %w
- failed to decode answer question batch response: %w
- failed to decode cancel question batch response: %w
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/d2567ab1a0b91e65.
Report an issue: GitHub.