{"record":{"id":"64096ea914556eff","repo":"pnpm/pnpm","slug":"registry-error-64096e","errorCode":"REGISTRY_ERROR","errorMessage":"Failed to ${action} package: ${response.status} ${response.statusText}. ${errorBody}","messagePattern":"Failed to (.+?) package: (.+?) (.+?)\\. (.+?)","errorType":"exception","errorClass":"PnpmError","httpStatus":null,"severity":"error","filePath":"pnpm11/registry-access/commands/src/access.ts","lineNumber":570,"sourceCode":"  }\n  return parsed.escapedName ?? encodeURIComponent(packageName).replace(/^%40/, '@')\n}\n\nasync function throwRegistryError (response: Response, action: string): Promise<never> {\n  const errorBody = sanitize(await readErrorBody(response))\n  if (response.status === 401) {\n    throw new PnpmError('UNAUTHORIZED', `You must be logged in to ${action} packages. ${errorBody}`)\n  }\n  if (response.status === 403) {\n    throw new PnpmError('FORBIDDEN', `You do not have permission to ${action} this package. ${errorBody}`)\n  }\n  if (response.status === 404) {\n    throw new PnpmError('PACKAGE_NOT_FOUND', `Package not found in registry. ${errorBody}`)\n  }\n  if (response.status === 422) {\n    throw new PnpmError('ACCESS_VALIDATION_ERROR', `Invalid request: ${errorBody}`)\n  }\n  throw new PnpmError('REGISTRY_ERROR', `Failed to ${action} package: ${response.status} ${response.statusText}. ${errorBody}`)\n}\n\nfunction sanitize (text: string): string {\n  let result = ''\n  for (let i = 0; i < text.length; i++) {\n    const code = text.charCodeAt(i)\n    if ((code > 31 && code !== 127) || code === 9 || code === 10) {\n      result += text[i]\n    }\n  }\n  return result\n}\n","sourceCodeStart":552,"sourceCodeEnd":583,"githubUrl":"https://github.com/pnpm/pnpm/blob/6261b7f388016d57ca6b90340342411cd1d0d00f/pnpm11/registry-access/commands/src/access.ts#L552-L583","documentation":"The catch-all of the access command's `throwRegistryError` helper: the registry answered with a status other than 401/403/404/422, so the CLI cannot map it to a specific cause and reports the raw status, statusText, and sanitized body. In practice this is 5xx server errors, gateway timeouts, and nonstandard codes returned by proxies or private registries.","triggerScenarios":"Any access subcommand whose HTTP request returns e.g. 500, 502, 503 from registry.npmjs.org during an incident, or from a corporate proxy/Artifactory in front of the registry; rare 409s or custom codes from non-npm registries.","commonSituations":"npm registry outage or degraded performance (check status.npmjs.org); a corporate proxy returning 502 for PUT/DELETE verbs; private registries that implement the access endpoints partially and return 500 for unsupported operations.","solutions":["Retry the command after a short wait — most 5xx responses are transient.","Check the registry's status page (status.npmjs.org for npmjs.org) if failures persist.","If behind a corporate proxy, verify the proxy permits the HTTP methods (PUT/DELETE) the access commands use.","Test basic connectivity to the same registry: `pnpm ping --registry <url>`."],"exampleFix":"# before\npnpm access set status=public @scope/pkg\n# ERR_PNPM_REGISTRY_ERROR Failed to set status for package: 503 Service Unavailable\n\n# after\n# wait for the registry incident to clear, verify, then retry\npnpm ping && pnpm access set status=public @scope/pkg","handlingStrategy":"retry","validationCode":"// pre-flight: confirm the registry is reachable before a mutation\nimport { execSync } from 'child_process'\n\nfunction assertRegistryReachable (registry = 'https://registry.npmjs.org/'): void {\n  execSync(`pnpm ping --registry ${registry}`, { stdio: 'pipe' })\n}","typeGuard":null,"tryCatchPattern":"async function withRegistryRetry (fn: () => Promise<string>, attempts = 3): Promise<string> {\n  for (let i = 0; i < attempts; i++) {\n    try {\n      return await fn()\n    } catch (err) {\n      const code = 'code' in err ? (err as { code: string }).code : ''\n      const msg = err instanceof Error ? err.message : ''\n      const transient = code === 'REGISTRY_ERROR' && /\\b(5\\d\\d|429)\\b/.test(msg)\n      if (!transient || i === attempts - 1) throw err\n      await new Promise((r) => setTimeout(r, 2 ** i * 1000))\n    }\n  }\n  throw new Error('unreachable')\n}","preventionTips":["Retry access mutations with exponential backoff — they are idempotent settings (visibility, MFA, grants).","Check status.npmjs.org before blaming your config when many commands fail at once.","Ensure corporate proxies allow the PUT/DELETE methods these endpoints use.","Alert on repeated 5xx from the same registry to catch proxy misconfiguration early."],"tags":["cli","access","npm-registry","http-5xx","transient"],"backgroundTag":"registry-request-failed","analyzedSha":"6261b7f388016d57ca6b90340342411cd1d0d00f","analyzedAt":"2026-08-17T18:30:54.750Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}