{"record":{"id":"ed2b12631b82784b","repo":"micro/go-micro","slug":"failed-to-create-request-w-ed2b12","errorCode":null,"errorMessage":"failed to create request: %w","messagePattern":"failed to create request: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ai/openai/openai.go","lineNumber":307,"sourceCode":"\t\treturn nil\n\t}\n\ts.closed = true\n\treturn s.body.Close()\n}\n\n// callAPI makes an HTTP request to the OpenAI API\nfunc (p *Provider) callAPI(ctx context.Context, req map[string]any) (*ai.Response, map[string]any, error) {\n\t// Marshal request\n\treqBody, err := json.Marshal(req)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"failed to marshal request: %w\", err)\n\t}\n\n\t// Build HTTP request\n\tapiURL := strings.TrimRight(p.opts.BaseURL, \"/\") + \"/v1/chat/completions\"\n\thttpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, apiURL, bytes.NewReader(reqBody))\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"failed to create request: %w\", err)\n\t}\n\n\t// Set headers\n\thttpReq.Header.Set(\"Content-Type\", \"application/json\")\n\thttpReq.Header.Set(\"Authorization\", \"Bearer \"+p.opts.APIKey)\n\n\t// Make request\n\thttpResp, err := http.DefaultClient.Do(httpReq)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"API request failed: %w\", err)\n\t}\n\tdefer httpResp.Body.Close()\n\n\t// Read response\n\trespBody, _ := io.ReadAll(httpResp.Body)\n\tif httpResp.StatusCode != http.StatusOK {\n\t\treturn nil, nil, ai.NewHTTPError(httpResp, respBody)\n\t}","sourceCodeStart":289,"sourceCodeEnd":325,"githubUrl":"https://github.com/micro/go-micro/blob/24529f140421a11a33b6999ab7944f2021cfd69c/ai/openai/openai.go#L289-L325","documentation":"Thrown in callAPI when http.NewRequestWithContext fails to build the POST request to /v1/chat/completions. net/http returns an error here only for an invalid method or an unparseable URL, so in practice this signals a malformed opts.BaseURL (empty, missing scheme, or containing invalid characters).","triggerScenarios":"Non-streaming completion calls with opts.BaseURL empty or malformed — e.g. \"api.openai.com\" without 'https://', containing spaces, or a misparsed config value; the failing URL is BaseURL + \"/v1/chat/completions\".","commonSituations":"Missing default BaseURL when the provider is constructed without WithBaseURL; env-driven config where an empty variable wipes the URL; copy-pasted endpoint missing the scheme; unusual characters from a templated config.","solutions":["Set a valid absolute BaseURL: WithBaseURL(\"https://api.openai.com\")","Ensure the URL includes the scheme and no spaces/invalid characters","Validate/normalize the URL (url.Parse) before provider construction","Fix config loading so empty env vars don't produce an empty BaseURL"],"exampleFix":"// before\nWithBaseURL(os.Getenv(\"OPENAI_BASE_URL\")) // empty in prod\n// after\nbase := os.Getenv(\"OPENAI_BASE_URL\")\nif base == \"\" {\n    base = \"https://api.openai.com\"\n}\n_ = WithBaseURL(base)","handlingStrategy":"validation","validationCode":"u, err := url.Parse(strings.TrimRight(baseURL, \"/\") + \"/v1/chat/completions\")\nif err != nil || u.Host == \"\" {\n    return fmt.Errorf(\"invalid BaseURL: %q\", baseURL)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate BaseURL with url.Parse at startup","Provide a sane default (https://api.openai.com) when config is empty","Fail fast on config load rather than at first API call"],"tags":["http","configuration","openai","url"],"backgroundTag":"invalid-url","analyzedSha":"24529f140421a11a33b6999ab7944f2021cfd69c","analyzedAt":"2026-09-01T02:52:24.923Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}