agalwood/Motrix · error · Error
registry responded ${res.status}
Error message
registry responded ${res.status} What it means
Thrown internally by RegistryClient.doRefresh when the registry HTTP response status is not 2xx and not 304 (res.ok is false). It is constructed as a plain Error whose message embeds the status code. Note: doRefresh catches this itself, logs 'registry refresh failed; keeping last-good', and returns the cached file or null — so callers of list()/get() normally observe stale/empty results rather than this Error directly.
Source
Thrown at src/core/plugin/registry/registry-client.ts:162
}, FETCH_TIMEOUT_MS)
})
try {
const headers: Record<string, string> = {}
if (this.cache?.etag) headers['if-none-match'] = this.cache.etag
const res = await Promise.race([
this.fetchImpl(this.url, { headers, signal: controller.signal }),
deadline,
])
if (res.status === 304 && this.cache) {
this.cache = { ...this.cache, fetchedAt: this.now() }
await this.persist()
return this.cache.file
}
if (!res.ok) {
throw new Error(`registry responded ${res.status}`)
}
const encoded = await Promise.race([
this.readBoundedResponse(res, controller),
deadline,
])
const raw: unknown = JSON.parse(encoded)
const file = RegistryFileSchema.parse(raw)
this.cache = {
cacheFormat: 2,
etag: res.headers.get('etag'),
fetchedAt: this.now(),
raw,
file,
}
await this.persist()
return file
} catch (error) {View on GitHub (pinned to 1a708ee577)
Solutions
- Check the embedded status: 404 -> verify this.url points at the live registry file; 401/403 -> check auth headers/proxy; 5xx -> transient, rely on the cache and retry.
- Confirm network/proxy reachability to the registry host.
- For test code, ensure the fetchImpl stub returns `Response.json(..., { status: 200 })`.
- Handle the downstream effect: list()/get() may return stale or null — surface a 'registry unavailable, using cache' notice to the user.
Example fix
// before (test stub returning default 404)
const client = new RegistryClient({ url: 'https://reg/app.json', fetchImpl: () => Promise.resolve(new Response()) })
// after
const client = new RegistryClient({ url: 'https://reg/app.json', fetchImpl: () => Promise.resolve(new Response(JSON.stringify(file), { status: 200, headers: { 'content-type': 'application/json' } })) }) Defensive patterns
Strategy: fallback
Try / catch
// doRefresh already swallows this and returns cache?.file ?? null.
// Callers of list()/get() should treat null/empty as 'registry unavailable':
const entries = await client.list(hostVersion)
if (entries.length === 0) {
notifyUser('Registry is unavailable; plugin list may be stale or empty.')
} Prevention
- Monitor the registry endpoint externally (uptime check) so 5xx is caught early.
- Keep the on-disk registry cache warm so doRefresh's fallback returns useful data.
- In tests, make the fetchImpl stub return Response.json(..., { status: 200 }).
- Distinguish 'no plugins' from 'fetch failed' by also checking the warn log emitted by doRefresh.
When it happens
Trigger: doRefresh() fetches this.url; the response has res.ok === false (e.g. 404, 401, 500, 502) and is not a 304. The fetchImpl is the real network fetch (or a test stub). Proxy/CDN returns an error page.
Common situations: Registry endpoint is misconfigured or moved (404). Auth/CORS changed (401/403). Registry server down or behind a failing proxy (5xx). Custom fetchImpl in tests returns a non-ok Response.
Related errors
- manifest fetch failed: HTTP ${res.status}
- manifest too large: ${text.length} > ${max}
- plugin.http.timeout
- plugin.http.network
- PLUGIN_MANIFEST_INVALID
AI-assisted analysis of agalwood/Motrix@1a708ee577 (2026-08-12).
Data as JSON: /api/errors/e1d5fdf6159fb0e7.
Report an issue: GitHub.