{"record":{"id":"7654be772a6b59c8","repo":"siyuan-note/siyuan","slug":"list-models-http-d","errorCode":null,"errorMessage":"list models HTTP %d","messagePattern":"list models HTTP (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/openai.go","lineNumber":358,"sourceCode":"\n\tendpoint := strings.TrimRight(apiBaseURL, \"/\") + \"/models\"\n\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif apiKey != \"\" {\n\t\treq.Header.Set(\"Authorization\", \"Bearer \"+apiKey)\n\t}\n\tresp, err := httpclient.NewUserAgentClient(nil).Do(req)\n\tif err != nil {\n\t\tlogging.LogErrorf(\"list models [%s] failed: %s\", apiBaseURL, err)\n\t\treturn\n\t}\n\tdefer resp.Body.Close()\n\tif resp.StatusCode < http.StatusOK || http.StatusBadRequest <= resp.StatusCode {\n\t\tbody, readErr := io.ReadAll(io.LimitReader(resp.Body, 64*1024))\n\t\tif readErr != nil {\n\t\t\terr = fmt.Errorf(\"list models HTTP %d\", resp.StatusCode)\n\t\t} else {\n\t\t\terr = fmt.Errorf(\"list models HTTP %d: %s\", resp.StatusCode, strings.TrimSpace(string(body)))\n\t\t}\n\t\tlogging.LogErrorf(\"list models [%s] failed: %s\", apiBaseURL, err)\n\t\treturn\n\t}\n\n\tpayload := &availableModelsPayload{}\n\tif err = json.NewDecoder(resp.Body).Decode(payload); err != nil {\n\t\tlogging.LogErrorf(\"decode models [%s] failed: %s\", apiBaseURL, err)\n\t\treturn\n\t}\n\tfor _, item := range payload.Data {\n\t\tid := strings.TrimSpace(item.ID)\n\t\tif id == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tmodels = append(models, AvailableModel{","sourceCodeStart":340,"sourceCodeEnd":376,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/util/openai.go#L340-L376","documentation":"ListAvailableModelsWithContext reads up to 64KB of an error response body to enrich the message. When the provider returns a non-2xx status AND reading that body itself fails (connection reset, mid-stream EOF, TLS close mid-read), the error degrades to this status-code-only form without the upstream reason.","triggerScenarios":"Provider returns 4xx/5xx on GET /models and then the connection drops before the body can be fully read; intermediary (proxy/CDN) closes an idle connection mid-response.","commonSituations":"Flaky upstream; upstream that sends headers then RST; aggressive proxy/CDN timeout; transient network blip during the models probe.","solutions":["Retry the model-list request once; transient body-read failures usually clear.","Verify network/proxy stability to the provider.","If persistent, curl the /models endpoint manually to see the real status and body.","Confirm apiBaseURL correctness (OpenAI-compatible providers need /v1)."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"var lastErr error\nfor i := 0; i < 2; i++ {\n    models, lastErr = util.ListAvailableModelsWithContext(apiKey, base, 30)\n    if lastErr == nil { break }\n    if !util.IsNetworkError(lastErr) { break }\n}","typeGuard":null,"tryCatchPattern":"models, err := util.ListAvailableModelsWithContext(key, base, 30)\nif err != nil && util.IsNetworkError(err) {\n    // retry once, then surface to the user\n}","preventionTips":["Retry transient body-read failures","Validate apiBaseURL format before listing","Use a stable network path to the provider"],"tags":["ai","openai","network","go","models"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}