janhq/jan · error · Error
Failed to fetch model catalog: ${error instanceof Error ? er
Error message
Failed to fetch model catalog: ${error instanceof Error ? error.message : 'Unknown error'} What it means
Thrown by the catch block of ModelService.fetchModelCatalog (default.ts:63). It wraps any error from the try block — the inner 'response not ok' throw [153], a network failure (DNS, offline, TLS), or a JSON parse failure — into a uniform 'Failed to fetch model catalog' message with the underlying error.message or 'Unknown error'.
Source
Thrown at web-app/src/services/models/default.ts:63
async fetchModels(): Promise<modelInfo[]> {
return this.getEngine()?.list() ?? []
}
async fetchModelCatalog(): Promise<ModelCatalog> {
try {
const response = await fetch(MODEL_CATALOG_URL)
if (!response.ok) {
throw new Error(
`Failed to fetch model catalog: ${response.status} ${response.statusText}`
)
}
const catalog: ModelCatalog = await response.json()
return catalog
} catch (error) {
console.error('Error fetching model catalog:', error)
throw new Error(
`Failed to fetch model catalog: ${error instanceof Error ? error.message : 'Unknown error'}`
)
}
}
async fetchLatestJanModel(): Promise<CatalogModel | null> {
try {
const response = await fetch(LATEST_JAN_MODEL_URL)
if (!response.ok) {
console.error(
`Failed to fetch latest Jan model: ${response.status} ${response.statusText}`
)
return null
}
const data = await response.json()
View on GitHub (pinned to fad3f12a14)
Solutions
- Distinguish network errors from HTTP-status errors so the inner [153] status is not lost — rethrow known Error instances unchanged.
- Verify network connectivity and DNS resolution for the catalog host.
- If a proxy intercepts with HTML, whitelist the catalog host.
- Cache the last successful catalog locally so a fetch failure degrades gracefully.
Example fix
// before
catch (error) {
console.error('Error fetching model catalog:', error)
throw new Error(`Failed to fetch model catalog: ${error instanceof Error ? error.message : 'Unknown error'}`)
}
// after: preserve the structured inner error instead of re-wrapping it
catch (error) {
console.error('Error fetching model catalog:', error)
if (error instanceof Error && error.message.startsWith('Failed to fetch model catalog')) throw error
throw new Error(`Failed to fetch model catalog: ${error instanceof Error ? error.message : 'Unknown error'}`)
} Defensive patterns
Strategy: try-catch
Validate before calling
async function safeFetchJson(url: string): Promise<ModelCatalog | null> {
const r = await fetch(url)
if (!r.ok) return null
try { return await r.json() as ModelCatalog } catch { return null }
} Type guard
function isModelCatalog(x: unknown): x is ModelCatalog {
return typeof x === 'object' && x !== null && Array.isArray((x as ModelCatalog).models)
} Try / catch
try {
return await this.fetchModelCatalog()
} catch (error) {
console.error('catalog unavailable, degrading to cache', error)
return getCachedCatalog() ?? []
} Prevention
- Do not re-wrap an Error that already carries the catalog-failure message — rethrow it.
- Distinguish fetch() network rejection from response.json() parse failure.
- Cache successful catalog fetches so a failure degrades gracefully.
- Show a non-blocking banner rather than failing the whole Hub view.
When it happens
Trigger: fetch() itself rejects (network unreachable, DNS failure, CORS, TLS error), response.json() throws (non-JSON body / empty body), or the inner [153] throw propagates into the catch and gets re-wrapped (note: the inner status detail is lost, replaced by the Error.message).
Common situations: User is offline; DNS for the catalog host fails; a proxy returns an HTML error page that fails JSON parsing; TLS cert expired on the catalog endpoint; the inner [153] error gets double-wrapped, obscuring the original status.
Related errors
- Failed to fetch model catalog: ${response.status} ${response
- Failed to fetch models from ${provider.provider}: ${result.s
- Failed to fetch models from ${provider.provider}: ${lastStat
- Failed to fetch HuggingFace repository: ${response.status} $
- Checksum mismatch for ${name}; the download was corrupt or t
AI-assisted analysis of janhq/jan@fad3f12a14 (2026-08-12).
Data as JSON: /api/errors/f279ce9beb027bae.
Report an issue: GitHub.