{"record":{"id":"6096660360477bf2","repo":"Hmbown/CodeWhale","slug":"the-runtime-returned-no-providers","errorCode":null,"errorMessage":"The Runtime returned no providers.","messagePattern":"The Runtime returned no providers\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/runtime_web/app.mjs","lineNumber":2001,"sourceCode":"    dom.newThreadDialog.showModal();\n    dom.newThreadCancel.focus({ preventScroll: true });\n    const generation = ++app.newThreadGeneration;\n    app.providerCatalog = null;\n    app.newThreadModels = [];\n    app.newThreadLoading = true;\n    dom.newThreadProvider.replaceChildren();\n    dom.newThreadModel.replaceChildren();\n    dom.newThreadModelInput.value = \"\";\n    setNewThreadStatus(\"Loading providers…\");\n    renderNewThreadCapability();\n    syncNewThreadControls();\n    try {\n      const catalog = await api(\"/v1/providers\");\n      if (generation !== app.newThreadGeneration || !dom.newThreadDialog.open) return;\n      const providers = Array.isArray(catalog?.providers)\n        ? catalog.providers.filter((provider) => String(provider?.id || \"\").trim())\n        : [];\n      if (providers.length === 0) throw new Error(\"The Runtime returned no providers.\");\n      app.providerCatalog = { ...catalog, providers };\n      for (const provider of providers) {\n        const option = document.createElement(\"option\");\n        option.value = provider.id;\n        setSafeText(option, providerOptionLabel(provider));\n        dom.newThreadProvider.append(option);\n      }\n      const defaults = newThreadDefaults(app.providerCatalog);\n      dom.newThreadProvider.value = defaults.providerId;\n      dom.newThreadProvider.disabled = false;\n      dom.newThreadProvider.focus({ preventScroll: true });\n      await loadNewThreadModels(defaults.providerId, defaults.model, generation);\n    } catch (error) {\n      if (generation !== app.newThreadGeneration || !dom.newThreadDialog.open) return;\n      app.newThreadLoading = false;\n      setNewThreadStatus(`Could not load providers: ${error.message}`, \"error\");\n      syncNewThreadControls();\n    }","sourceCodeStart":1983,"sourceCodeEnd":2019,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/runtime_web/app.mjs#L1983-L2019","documentation":"Thrown when the /v1/providers catalog request succeeds but, after filtering out entries without a usable id, no providers remain. The new-thread dialog cannot offer any provider/model choice, so the loader fails loudly rather than rendering an empty picker.","triggerScenarios":"api('/v1/providers') returns a catalog whose `providers` is not an array or contains only entries with blank/missing `id`; the filtered providers.length === 0 path throws.","commonSituations":"No providers configured in the Runtime (empty config); malformed provider entries in the Runtime config causing them to be filtered out; a Runtime build returning a different catalog payload shape; a proxy returning a valid-JSON but empty body.","solutions":["Configure at least one provider in the Codewhale Runtime config and restart `codewhale web`","Inspect GET /v1/providers and confirm each entry has a non-empty `id`","Fix malformed provider entries (missing id) that the client filter drops","Verify the Runtime build matches the browser bundle's expected catalog shape"],"exampleFix":"// before: rendering whatever arrives and failing later\napp.providerCatalog = catalog;\n// after: fail loud on an empty catalog, as the loader does\nconst providers = (catalog?.providers || []).filter(p => String(p?.id || '').trim());\nif (!providers.length) throw new Error('no usable providers; check Runtime provider config');","handlingStrategy":"try-catch","validationCode":"const providers = (catalog?.providers || []).filter(p => String(p?.id || '').trim()); if (providers.length === 0) showConfigWarning();","typeGuard":"const hasProviders = (c) => Array.isArray(c?.providers) && c.providers.some(p => String(p?.id || '').trim());","tryCatchPattern":"try { await openNewThreadDialog(); } catch (e) { if (String(e.message).includes('no providers')) showToast('Configure a provider in the Runtime config.'); }","preventionTips":["Configure at least one provider before launching the web UI","Give every provider entry a non-empty id","Validate Runtime provider config at startup","Verify /v1/providers returns usable entries after config changes"],"tags":["provider-catalog","empty-result","configuration"],"backgroundTag":"empty-result-set","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}