{"record":{"id":"9630f298de957424","repo":"pnpm/pnpm","slug":"err-pnpm-unsupported-resolution-type","errorCode":"ERR_PNPM_UNSUPPORTED_RESOLUTION_TYPE","errorMessage":"Cannot fetch dependency with custom resolution type \"${resolution.type}\". Custom resolutions must be handled by custom fetchers.","messagePattern":"Cannot fetch dependency with custom resolution type \"(.+?)\"\\. Custom resolutions must be handled by custom fetchers\\.","errorType":"exception","errorClass":"PnpmError","httpStatus":null,"severity":"error","filePath":"pnpm11/fetching/pick-fetcher/src/index.ts","lineNumber":72,"sourceCode":"            },\n            { resolutionNeedsFetch }\n          ) as FetchFunction\n        }\n      }\n    }\n  }\n\n  return pickBuiltinFetcher(fetcherByHostingType, resolution)\n}\n\nfunction isCustomFetcherDelegation (result: FetchResult | CustomFetcherDelegation): result is CustomFetcherDelegation {\n  return result != null && typeof result === 'object' && 'delegate' in result && !('filesMap' in result)\n}\n\nfunction pickBuiltinFetcher (fetcherByHostingType: Fetchers, resolution: AtomicResolution): PickedFetcher {\n  const fetcherType = classifyResolution(resolution)\n  if (fetcherType === 'custom') {\n    throw new PnpmError(\n      'UNSUPPORTED_RESOLUTION_TYPE',\n      `Cannot fetch dependency with custom resolution type \"${resolution.type}\". ` +\n      'Custom resolutions must be handled by custom fetchers.'\n    )\n  }\n\n  const fetch = fetcherByHostingType[fetcherType]\n\n  if (!fetch) {\n    throw new Error(`Fetching for dependency type \"${resolution.type ?? 'tarball'}\" is not supported`)\n  }\n\n  return fetch\n}\n","sourceCodeStart":54,"sourceCodeEnd":87,"githubUrl":"https://github.com/pnpm/pnpm/blob/6261b7f388016d57ca6b90340342411cd1d0d00f/pnpm11/fetching/pick-fetcher/src/index.ts#L54-L87","documentation":"pick-fetcher classifies each resolution and dispatches to a built-in fetcher (registry tarball, git, local dir, binary, ...). When classifyResolution returns 'custom', no built-in exists by construction — custom resolution types are only fetchable through custom fetchers registered programmatically by an embedding application. Hitting this from a stock install means a custom resolution leaked into the graph without its fetcher.","triggerScenarios":"A lockfile/resolution record with a custom type field reaches pickBuiltinFetcher (and its caller did not supply a matching custom fetcher, or earlier custom-fetcher delegation did not match). Typical with plugins or programmatic pipelines that drop their fetcher registration.","commonSituations":"Lockfiles authored for a plugin-based pnpm wrapper run under plain pnpm; programmatic consumers that build the fetchers map but forget to include their custom fetcher; version skew after a wrapper upgrade.","solutions":["Remove the custom resolution from package.json and the lockfile, or replace it with a supported protocol (npm, git, tarball URL, file:, link:)","If you depend on custom resolutions, run installs through the tool that registers the matching custom fetcher","Regenerate the lockfile in the environment that owns those resolutions"],"exampleFix":"// before\n{ \"dependencies\": { \"mydb\": \"myproto://host/thing\" } }\n\n// after\n{ \"dependencies\": { \"mydb\": \"github:owner/mydb-adapter\" } }","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"type BuiltinResolutionType = 'registry' | 'git' | 'tarball' | 'directory' | 'binary'\n\nconst CUSTOM_TYPES = new Set(['custom']) // whatever your pipeline defines\n\nfunction needsCustomFetcher (resolution: { type?: string }): boolean {\n  return resolution.type != null && CUSTOM_TYPES.has(resolution.type)\n}\n\n// before building the fetcher pipeline\nif (graphResolutions.some(needsCustomFetcher) && customFetchers.length === 0) {\n  throw new Error('lockfile contains custom resolutions but no custom fetcher is registered')\n}","tryCatchPattern":"try {\n  await pickFetcherAndFetch(resolution)\n} catch (err) {\n  if (err instanceof PnpmError && err.code === 'ERR_PNPM_UNSUPPORTED_RESOLUTION_TYPE') {\n    // No retry will help: register the fetcher or strip the resolution\n    throw new Error(`no fetcher for custom type '${resolution.type}'; register one or use a builtin protocol`, { cause: err })\n  }\n  throw err\n}","preventionTips":["If your tool supports custom resolutions, register the custom fetchers in the same code path that reads the lockfile","Fail fast at startup when the lockfile declares custom types but no fetchers are wired","Keep stock installs on builtin protocols (npm/git/tarball/file/link)"],"tags":["resolution","custom-fetcher","plugin","dependency"],"backgroundTag":"unsupported-resolution-type","analyzedSha":"6261b7f388016d57ca6b90340342411cd1d0d00f","analyzedAt":"2026-08-17T18:30:54.750Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}