{"record":{"id":"84e7c521afa9ccbc","repo":"charmbracelet/crush","slug":"failed-to-decode-project-init-response-w","errorCode":null,"errorMessage":"failed to decode project init response: %w","messagePattern":"failed to decode project init response: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/client/config.go","lineNumber":180,"sourceCode":"\treturn nil\n}\n\n// ProjectNeedsInitialization checks if the project needs\n// initialization.\nfunc (c *Client) ProjectNeedsInitialization(ctx context.Context, id string) (bool, error) {\n\trsp, err := c.get(ctx, fmt.Sprintf(\"/workspaces/%s/project/needs-init\", id), nil, nil)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"failed to check project init: %w\", err)\n\t}\n\tdefer rsp.Body.Close()\n\tif rsp.StatusCode != http.StatusOK {\n\t\treturn false, fmt.Errorf(\"failed to check project init: status code %d\", rsp.StatusCode)\n\t}\n\tvar result struct {\n\t\tNeedsInit bool `json:\"needs_init\"`\n\t}\n\tif err := json.NewDecoder(rsp.Body).Decode(&result); err != nil {\n\t\treturn false, fmt.Errorf(\"failed to decode project init response: %w\", err)\n\t}\n\treturn result.NeedsInit, nil\n}\n\n// MarkProjectInitialized marks the project as initialized on the\n// server.\nfunc (c *Client) MarkProjectInitialized(ctx context.Context, id string) error {\n\trsp, err := c.post(ctx, fmt.Sprintf(\"/workspaces/%s/project/init\", id), nil, nil, nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to mark project initialized: %w\", err)\n\t}\n\tdefer rsp.Body.Close()\n\tif rsp.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"failed to mark project initialized: status code %d\", rsp.StatusCode)\n\t}\n\treturn nil\n}\n","sourceCodeStart":162,"sourceCodeEnd":198,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/client/config.go#L162-L198","documentation":"After a 200 response, ProjectNeedsInitialization decodes the JSON body expecting {\"needs_init\": bool}. A body that is empty, malformed, or has the wrong shape produces this error. It indicates a server/client contract mismatch rather than a network problem.","triggerScenarios":"Calling ProjectNeedsInitialization when the response body is not decodable JSON: empty body from a misconfigured proxy, HTML error page injected by an auth wall, or a server version returning a different field name/type for needs_init.","commonSituations":"Reverse proxy or captive portal returning HTML; server/client version skew after an API field rename; gzip/compression misconfiguration producing garbage bytes; server returning 200 with an empty body on internal errors.","solutions":["Dump the raw response body to see what the server actually returned","Check client/server version compatibility for the needs_init field","Bypass or reconfigure any proxy that could inject HTML into the response","Upgrade the client or server so both agree on the JSON contract"],"exampleFix":"// before\nneedsInit, err := client.ProjectNeedsInitialization(ctx, id)\nif err != nil {\n    return err\n}\n// after\nneedsInit, err := client.ProjectNeedsInitialization(ctx, id)\nif err != nil {\n    log.Printf(\"needs-init decode failed (server contract mismatch?): %v\", err)\n    return err\n}","handlingStrategy":"type-guard","validationCode":"// Verify the server speaks JSON before trusting decoded bodies\nresp, err := http.Get(client.BaseURL() + \"/healthz\")\nif err != nil {\n    return err\n}\nct := resp.Header.Get(\"Content-Type\")\nresp.Body.Close()\nif !strings.HasPrefix(ct, \"application/json\") {\n    return fmt.Errorf(\"server returned non-JSON content type: %s\", ct)\n}","typeGuard":"func looksLikeJSON(b []byte) bool {\n    t := bytes.TrimSpace(b)\n    return len(t) > 0 && (t[0] == '{' || t[0] == '[')\n}","tryCatchPattern":"needsInit, err := c.ProjectNeedsInitialization(ctx, id)\nif err != nil {\n    if strings.Contains(err.Error(), \"failed to decode\") {\n        // contract mismatch: log payload, fall back to prompting the user\n        return fallbackInteractiveInit()\n    }\n    return err\n}","preventionTips":["Assert Content-Type: application/json on API responses in server tests","Pin compatible client/server versions; bump them together","Bypass or correctly configure proxies that can inject HTML with 200 status","Fuzz or golden-test response payloads when changing the API schema"],"tags":["json","http-client","api-contract"],"backgroundTag":"json-decode-failed","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}