{"record":{"id":"f304c69603776d74","repo":"gastownhall/beads","slug":"failed-to-create-request-w","errorCode":null,"errorMessage":"failed to create request: %w","messagePattern":"failed to create request: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/gitlab/client.go","lineNumber":125,"sourceCode":"\t\t}\n\t\treqBody = bytes.NewReader(jsonBody)\n\t}\n\n\tvar lastErr error\n\tfor attempt := 0; attempt <= MaxRetries; attempt++ {\n\t\t// Reset body reader at top of loop so retries after network errors\n\t\t// don't send empty bodies (the reader may be at EOF).\n\t\tif body != nil {\n\t\t\tjsonBody, err := json.Marshal(body)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, nil, fmt.Errorf(\"failed to marshal request body: %w\", err)\n\t\t\t}\n\t\t\treqBody = bytes.NewReader(jsonBody)\n\t\t}\n\n\t\treq, err := http.NewRequestWithContext(ctx, method, urlStr, reqBody)\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"failed to create request: %w\", err)\n\t\t}\n\n\t\treq.Header.Set(\"PRIVATE-TOKEN\", c.Token)\n\t\treq.Header.Set(\"Content-Type\", \"application/json\")\n\n\t\tresp, err := c.HTTPClient.Do(req)\n\t\tif err != nil {\n\t\t\tlastErr = fmt.Errorf(\"request failed (attempt %d/%d): %w\", attempt+1, MaxRetries+1, err)\n\t\t\tcontinue\n\t\t}\n\n\t\t// Limit response body to 50MB to prevent OOM from malformed responses.\n\t\tconst maxResponseSize = 50 * 1024 * 1024\n\t\trespBody, err := io.ReadAll(io.LimitReader(resp.Body, maxResponseSize))\n\t\t_ = resp.Body.Close() // Best effort: HTTP body close; connection may be reused regardless\n\t\tif err != nil {\n\t\t\tlastErr = fmt.Errorf(\"failed to read response (attempt %d/%d): %w\", attempt+1, MaxRetries+1, err)\n\t\t\tcontinue","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/gitlab/client.go#L107-L143","documentation":"http.NewRequestWithContext failed to construct the outbound request. Since method and URL are built internally by the client, this almost always means the resolved URL string is malformed (bad base URL configuration) or the context/method combination is invalid. The error is wrapped and returned without retrying.","triggerScenarios":"A misconfigured base URL (e.g. missing scheme: 'gitlab.example.com/api/v4' instead of 'https://...'), control characters in the URL, or an invalid URL resulting from buildURL parameter concatenation, causing url.Parse inside NewRequestWithContext to fail.","commonSituations":"Setting GitLabURL or config base URL without the https:// scheme; trailing spaces in an env-provided URL; project/group paths containing characters that break URL parsing; proxy env vars injecting garbage.","solutions":["Verify the configured base URL includes a valid scheme and host (https://gitlab.com/api/v4)","Trim whitespace from URL config values read from environment or YAML","Check for special characters in project/group path segments and URL-encode them","Log the final urlStr by reproducing buildURL with your inputs to spot the malformed piece"],"exampleFix":"// before\nBaseURL: \"gitlab.example.com/api/v4\"\n// after\nBaseURL: \"https://gitlab.example.com/api/v4\"","handlingStrategy":"validation","validationCode":"u, err := url.Parse(cfg.BaseURL)\nif err != nil || u.Scheme == \"\" || u.Host == \"\" {\n\treturn fmt.Errorf(\"invalid GitLab base URL: %q\", cfg.BaseURL)\n}","typeGuard":"func validBaseURL(s string) bool {\n\tu, err := url.Parse(s)\n\treturn err == nil && (u.Scheme == \"http\" || u.Scheme == \"https\") && u.Host != \"\"\n}","tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"failed to create request\") {\n\treturn fmt.Errorf(\"check GitLab base URL config (scheme/host): %w\", err)\n}","preventionTips":["Always include the https:// scheme in configured base URLs","Trim whitespace from URL values read from env/YAML","URL-encode project/group path segments containing special characters","Smoke-test the URL with curl before wiring it into config"],"tags":["url","configuration","gitlab"],"backgroundTag":"malformed-url","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}