{"record":{"id":"5ce7f78b1e245cdc","repo":"siyuan-note/siyuan","slug":"unexpected-status-code-d","errorCode":null,"errorMessage":"unexpected status code: %d","messagePattern":"unexpected status code: (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"kernel/agent/modelmeta_online.go","lineNumber":195,"sourceCode":"\t}\n\tmodelsDevState.catalog = catalog\n\tmodelsDevState.expiresAt = completedAt.Add(modelsDevCatalogCacheTTL)\n\tmodelsDevState.retryAt = time.Time{}\n\treturn nil\n}\n\nfunc fetchModelsDevContextCatalog(ctx context.Context) (*modelsDevContextCatalog, error) {\n\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, modelsDevEndpoint, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tresp, err := httpclient.NewUserAgentClient(nil).Do(req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer resp.Body.Close()\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"unexpected status code: %d\", resp.StatusCode)\n\t}\n\n\tproviders := map[string]modelsDevProvider{}\n\tlimited := io.LimitReader(resp.Body, modelsDevCatalogMaxBytes+1)\n\tif err = json.NewDecoder(limited).Decode(&providers); err != nil {\n\t\treturn nil, err\n\t}\n\tif len(providers) == 0 {\n\t\treturn nil, errors.New(\"empty catalog\")\n\t}\n\n\tcatalog := &modelsDevContextCatalog{\n\t\tproviders: map[string]*modelsDevProviderCatalog{},\n\t\tmodels:    map[string]int{},\n\t\tsuffixes:  map[string]int{},\n\t}\n\tambiguousModels := map[string]bool{}\n\tambiguousSuffixes := map[string]bool{}","sourceCodeStart":177,"sourceCodeEnd":213,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/agent/modelmeta_online.go#L177-L213","documentation":"fetchModelsDevContextCatalog requires an HTTP 200 from the models.dev context-length catalog endpoint and fails with this error for any other status (404, 403, 429, 5xx, etc.). The status code is embedded so the caller knows exactly how the upstream request failed; refreshModelsDevContextCatalog then typically keeps any previously cached catalog.","triggerScenarios":"The GET to the models.dev catalog URL returns a non-200 status — endpoint moved/renamed, rate limited (429), blocked by auth/proxy (403), or upstream outage (5xx).","commonSituations":"models.dev is temporarily down or rate-limiting your IP; a corporate proxy intercepts the request; the catalog URL changed in a newer SiYuan version while an old build still requests the old path; intermittent 5xx during provider incidents.","solutions":["Retry later — most non-200 cases (429/5xx) are transient upstream issues","Check network/proxy configuration that may return error pages (403/502) instead of the catalog","Verify the app version's catalog URL is still valid; update SiYuan if the endpoint moved","Rely on the cached catalog if present; the failure only blocks refresh, not existing metadata"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"req, _ := http.NewRequest(\"GET\", catalogURL, nil)\nresp, err := httpclient.NewUserAgentClient(nil).Do(req)\nif err == nil && resp.StatusCode != http.StatusOK { log.Printf(\"catalog refresh skipped, status %d; keeping cached catalog\", resp.StatusCode) }","typeGuard":null,"tryCatchPattern":"if err != nil { log.Printf(\"context catalog refresh failed: %v; using cached catalog\", err); return cachedCatalog, nil }","preventionTips":["Always keep the last successfully fetched catalog as a fallback","Back off on 429 responses and honor Retry-After headers","Pin an app version known to use a valid catalog URL"],"tags":["network","http","catalog","upstream"],"backgroundTag":"http-non-200-response","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}