{"record":{"id":"8f135c934ddc0652","repo":"charmbracelet/crush","slug":"failed-to-check-project-init-w","errorCode":null,"errorMessage":"failed to check project init: %w","messagePattern":"failed to check project init: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/client/config.go","lineNumber":170,"sourceCode":"\t\tScope      config.Scope `json:\"scope\"`\n\t\tProviderID string       `json:\"provider_id\"`\n\t}{Scope: scope, ProviderID: providerID}), http.Header{\"Content-Type\": []string{\"application/json\"}})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to refresh OAuth token: %w\", err)\n\t}\n\tdefer rsp.Body.Close()\n\tif rsp.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"failed to refresh OAuth token: status code %d\", rsp.StatusCode)\n\t}\n\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)","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/client/config.go#L152-L188","documentation":"ProjectNeedsInitialization performs GET /workspaces/{id}/project/needs-init and wraps any transport-level failure of that request with this error. The boolean result could not be obtained because the request itself failed before a response arrived.","triggerScenarios":"Calling Client.ProjectNeedsInitialization(ctx, id) when the GET request fails at the transport layer: unreachable server, reset connection, TLS error, or context cancellation.","commonSituations":"Offline development machine; server not started yet during local setup; wrong base URL or port in client configuration; corporate proxy blocking the call at project bootstrap time.","solutions":["Confirm the server is running and the client base URL is correct","Check ctx cancellation/deadline — a cancelled context surfaces as a wrapped request error","Retry on transient network errors before giving up on project initialization","Inspect the wrapped cause with errors.As to classify timeout vs connection refused"],"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    if isRetryable(err) {\n        needsInit, err = client.ProjectNeedsInitialization(ctx, id)\n    }\n    if err != nil {\n        return fmt.Errorf(\"bootstrap: %w\", err)\n    }\n}","handlingStrategy":"retry","validationCode":"// Check the server is reachable before bootstrap queries\nresp, err := http.Get(client.BaseURL() + \"/healthz\")\nif err != nil || resp.StatusCode != http.StatusOK {\n    return fmt.Errorf(\"server not ready\")\n}\nresp.Body.Close()","typeGuard":"func isTransportError(err error) bool {\n    var netErr net.Error\n    return errors.As(err, &netErr)\n}","tryCatchPattern":"needsInit, err := c.ProjectNeedsInitialization(ctx, id)\nif err != nil {\n    var netErr net.Error\n    if errors.As(err, &netErr) {\n        return retryWithBackoff(ctx, func() error { _, err = c.ProjectNeedsInitialization(ctx, id); return err })\n    }\n    return err\n}","preventionTips":["Gate bootstrap flows behind a server health check","Pass contexts with sane deadlines instead of background contexts","Cache the last known needs-init state to degrade gracefully when offline","Surface wrapped network causes to logs for faster diagnosis"],"tags":["http-client","network","bootstrap"],"backgroundTag":"http-request-failed","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}