{"record":{"id":"741013bfd20d6fb2","repo":"gastownhall/beads","slug":"request-failed-w-741013","errorCode":null,"errorMessage":"request failed: %w","messagePattern":"request failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/notion/client.go","lineNumber":282,"sourceCode":"\n\trequestURL := path\n\tif !strings.HasPrefix(requestURL, \"http://\") && !strings.HasPrefix(requestURL, \"https://\") {\n\t\trequestURL = strings.TrimSuffix(c.BaseURL, \"/\") + path\n\t}\n\treq, err := http.NewRequestWithContext(ctx, method, requestURL, bodyReader)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"create request: %w\", err)\n\t}\n\treq.Header.Set(\"Authorization\", \"Bearer \"+c.Token)\n\treq.Header.Set(\"Notion-Version\", c.NotionVersion)\n\treq.Header.Set(\"Accept\", \"application/json\")\n\tif requestBody != nil {\n\t\treq.Header.Set(\"Content-Type\", \"application/json\")\n\t}\n\n\tresp, err := httpClient.Do(req) //nolint:gosec // G704: URL is constructed from configured Notion API base, not user input\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"request failed: %w\", err)\n\t}\n\tdefer func() { _ = resp.Body.Close() }()\n\n\tbody, err := io.ReadAll(io.LimitReader(resp.Body, maxResponseBytes))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"read response: %w\", err)\n\t}\n\tif resp.StatusCode >= 200 && resp.StatusCode < 300 {\n\t\treturn body, nil\n\t}\n\n\tvar apiErr struct {\n\t\tCode    string `json:\"code\"`\n\t\tMessage string `json:\"message\"`\n\t}\n\tif err := json.Unmarshal(body, &apiErr); err == nil && apiErr.Message != \"\" {\n\t\treturn nil, fmt.Errorf(\"Notion API error %s (%d): %s\", apiErr.Code, resp.StatusCode, apiErr.Message)\n\t}","sourceCodeStart":264,"sourceCodeEnd":300,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/notion/client.go#L264-L300","documentation":"The HTTP transport itself failed: httpClient.Do returned an error before any HTTP response was received (DNS failure, connection refused/reset, TLS handshake error, timeout, or request cancellation via ctx). The error is wrapped as 'request failed: %w' with the underlying net/http error in the chain.","triggerScenarios":"Network unreachable or DNS cannot resolve api.notion.com; corporate proxy/firewall blocking outbound 443; TLS interception with untrusted certs; custom c.HTTPClient with a too-short timeout; context cancelled mid-request.","commonSituations":"Running in an air-gapped/locked-down CI environment without egress; VPN down; invalid corporate proxy not configured via HTTPS_PROXY; machine clock skew breaking TLS; custom http.Client{Timeout: 100 * time.Millisecond} in tests.","solutions":["Read the wrapped error to identify the class (dial tcp / tls / context deadline) and fix accordingly.","Verify outbound connectivity: curl -v https://api.notion.com/v1/users/me from the same host.","Configure proxy env vars (HTTPS_PROXY) if behind a corporate proxy, or trust the corporate CA.","Increase or reset the http.Client timeout used for the Notion client; retry with backoff for transient failures."],"exampleFix":"// before\nclient := &notion.Client{Token: tok, HTTPClient: &http.Client{Timeout: 50 * time.Millisecond}}\n\n// after\nclient := &notion.Client{Token: tok, HTTPClient: &http.Client{Timeout: 30 * time.Second}}","handlingStrategy":"retry","validationCode":"req, err := http.NewRequestWithContext(ctx, http.MethodGet, \"https://api.notion.com/v1/users/me\", nil)\nif err == nil {\n    if _, err := http.DefaultClient.Do(req); err != nil {\n        return fmt.Errorf(\"notion API unreachable: %w\", err)\n    }\n}","typeGuard":null,"tryCatchPattern":"var netErr net.Error\nif errors.As(err, &netErr) && netErr.Timeout() {\n    // backoff and retry\n}","preventionTips":["Set a sane http.Client timeout (e.g. 30s) instead of very short or zero.","Verify egress/proxy/firewall access to api.notion.com in each environment (CI, prod).","Use context timeouts so cancellations are intentional and observable.","Implement exponential backoff for transient transport errors."],"tags":["notion","network","http-client","connectivity"],"backgroundTag":"request-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}