{"record":{"id":"d2bd9f090a4df1b5","repo":"micro/go-micro","slug":"stream-api-error-s-s-d2bd9f","errorCode":null,"errorMessage":"stream API error (%s): %s","messagePattern":"stream API error \\((.+?)\\): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ai/ollama/ollama.go","lineNumber":354,"sourceCode":"\tapiURL := strings.TrimRight(p.opts.BaseURL, \"/\") + p.streamPath()\n\thttpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, apiURL, bytes.NewReader(reqBody))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create stream request: %w\", err)\n\t}\n\thttpReq.Header.Set(\"Content-Type\", \"application/json\")\n\thttpReq.Header.Set(\"Accept\", \"text/event-stream\")\n\tif p.opts.APIKey != \"\" {\n\t\thttpReq.Header.Set(\"Authorization\", \"Bearer \"+p.opts.APIKey)\n\t}\n\n\thttpResp, err := http.DefaultClient.Do(httpReq)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"stream API request failed: %w\", err)\n\t}\n\tif httpResp.StatusCode != http.StatusOK {\n\t\tdefer httpResp.Body.Close()\n\t\trespBody, _ := io.ReadAll(httpResp.Body)\n\t\treturn nil, fmt.Errorf(\"stream API error (%s): %s\", httpResp.Status, string(respBody))\n\t}\n\n\treturn &sseStream{body: httpResp.Body, scanner: bufio.NewScanner(httpResp.Body)}, nil\n}\n\n// buildOpenAIMessages converts an ai.Request into the OpenAI chat message format.\nfunc buildOpenAIMessages(req *ai.Request) []map[string]any {\n\tmessages := []map[string]any{}\n\tif req.SystemPrompt != \"\" {\n\t\tmessages = append(messages, map[string]any{\"role\": \"system\", \"content\": req.SystemPrompt})\n\t}\n\tfor _, m := range req.Messages {\n\t\tmessages = append(messages, map[string]any{\"role\": m.Role, \"content\": m.Content})\n\t}\n\tif req.Prompt != \"\" {\n\t\tmessages = append(messages, map[string]any{\"role\": \"user\", \"content\": req.Prompt})\n\t}\n\treturn messages","sourceCodeStart":336,"sourceCodeEnd":372,"githubUrl":"https://github.com/micro/go-micro/blob/24529f140421a11a33b6999ab7944f2021cfd69c/ai/ollama/ollama.go#L336-L372","documentation":"The Ollama Cloud OpenAI-compatible endpoint returned a non-200 HTTP status for a streaming chat request. The error embeds the HTTP status string (e.g. '401 Unauthorized') and the raw response body, which usually holds the server's JSON error explaining why.","triggerScenarios":"Stream() in cloud mode receives any status != 200: 401/403 (bad/missing API key), 404 (wrong path/BaseURL), 400 (malformed model or request), 429/5xx from ollama.com.","commonSituations":"Missing or expired OLLAMA_API_KEY, using an API key without cloud access, BaseURL pointing to /v1 incorrectly, requesting a model name that doesn't exist on ollama.com, rate limiting.","solutions":["Read the body in the error message — it contains the server's reason.","401/403: set a valid API key via WithAPIKey or the OLLAMA_API_KEY env var.","404: fix BaseURL so it ends at the host root or /v1, not a duplicated path.","400: verify the model name exists on the cloud endpoint.","429/5xx: back off and retry; the server is rate-limiting or unhealthy."],"exampleFix":"// before\nprovider := ai.NewProvider(\"ollama\", ai.WithBaseURL(\"https://ollama.com/v1\")) // no API key -> 401\n// after\nprovider := ai.NewProvider(\"ollama\", ai.WithBaseURL(\"https://ollama.com/v1\"), ai.WithAPIKey(os.Getenv(\"OLLAMA_API_KEY\")))","handlingStrategy":"try-catch","validationCode":"if os.Getenv(\"OLLAMA_API_KEY\") == \"\" {\n    return errors.New(\"OLLAMA_API_KEY is required for ollama.com cloud endpoints\")\n}","typeGuard":null,"tryCatchPattern":"stream, err := provider.Stream(ctx, req)\nif err != nil {\n    var apiErr *ApiError // or match on status substring\n    msg := err.Error()\n    switch {\n    case strings.Contains(msg, \"401\"), strings.Contains(msg, \"403\"):\n        return errors.New(\"authentication failed: check OLLAMA_API_KEY\")\n    case strings.Contains(msg, \"429\"):\n        // back off and retry\n    default:\n        return err\n    }\n}","preventionTips":["Validate the API key with a cheap models-list call before streaming.","Never hardcode keys; load from env/secret manager and check presence at boot.","Pin a correct BaseURL constant instead of assembling it ad hoc.","Monitor for 429s and implement client-side rate limiting."],"tags":["http-status","authentication","streaming","ollama-cloud"],"backgroundTag":"http-non-200-response","analyzedSha":"24529f140421a11a33b6999ab7944f2021cfd69c","analyzedAt":"2026-09-01T02:52:24.923Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}