{"record":{"id":"e1d5fdf6159fb0e7","repo":"agalwood/Motrix","slug":"registry-responded-res-status","errorCode":null,"errorMessage":"registry responded ${res.status}","messagePattern":"registry responded (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/core/plugin/registry/registry-client.ts","lineNumber":162,"sourceCode":"      }, FETCH_TIMEOUT_MS)\n    })\n\n    try {\n      const headers: Record<string, string> = {}\n      if (this.cache?.etag) headers['if-none-match'] = this.cache.etag\n\n      const res = await Promise.race([\n        this.fetchImpl(this.url, { headers, signal: controller.signal }),\n        deadline,\n      ])\n\n      if (res.status === 304 && this.cache) {\n        this.cache = { ...this.cache, fetchedAt: this.now() }\n        await this.persist()\n        return this.cache.file\n      }\n      if (!res.ok) {\n        throw new Error(`registry responded ${res.status}`)\n      }\n\n      const encoded = await Promise.race([\n        this.readBoundedResponse(res, controller),\n        deadline,\n      ])\n      const raw: unknown = JSON.parse(encoded)\n      const file = RegistryFileSchema.parse(raw)\n      this.cache = {\n        cacheFormat: 2,\n        etag: res.headers.get('etag'),\n        fetchedAt: this.now(),\n        raw,\n        file,\n      }\n      await this.persist()\n      return file\n    } catch (error) {","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/agalwood/Motrix/blob/1a708ee57746c434e2c67a44bbf0906a976afea4/src/core/plugin/registry/registry-client.ts#L144-L180","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before (test stub returning default 404)\nconst client = new RegistryClient({ url: 'https://reg/app.json', fetchImpl: () => Promise.resolve(new Response()) })\n\n// after\nconst client = new RegistryClient({ url: 'https://reg/app.json', fetchImpl: () => Promise.resolve(new Response(JSON.stringify(file), { status: 200, headers: { 'content-type': 'application/json' } })) })","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"// doRefresh already swallows this and returns cache?.file ?? null.\n// Callers of list()/get() should treat null/empty as 'registry unavailable':\nconst entries = await client.list(hostVersion)\nif (entries.length === 0) {\n  notifyUser('Registry is unavailable; plugin list may be stale or empty.')\n}","preventionTips":["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."],"tags":["plugin","registry","network","http"],"backgroundTag":null,"analyzedSha":"1a708ee57746c434e2c67a44bbf0906a976afea4","analyzedAt":"2026-08-12T16:18:09.346Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}