{"record":{"id":"f87b1b189cff0c75","repo":"pnpm/pnpm","slug":"invalid-catalog-entry-for-alias-expected-strin","errorCode":null,"errorMessage":"Invalid catalog entry for ${alias}. Expected string, but found: ${typeof specifier}","messagePattern":"Invalid catalog entry for (.+?)\\. Expected string, but found: (.+?)","errorType":"exception","errorClass":"InvalidWorkspaceManifestError","httpStatus":null,"severity":"error","filePath":"pnpm11/workspace/workspace-manifest-reader/src/catalogs.ts","lineNumber":26,"sourceCode":"  [dependencyName: string]: string\n}\n\nexport function assertValidWorkspaceManifestCatalog (manifest: { packages?: readonly string[], catalog?: unknown }): asserts manifest is { catalog?: WorkspaceCatalog } {\n  if (manifest.catalog == null) {\n    return\n  }\n\n  if (Array.isArray(manifest.catalog)) {\n    throw new InvalidWorkspaceManifestError('Expected catalog field to be an object, but found - array')\n  }\n\n  if (typeof manifest.catalog !== 'object') {\n    throw new InvalidWorkspaceManifestError(`Expected catalog field to be an object, but found - ${typeof manifest.catalog}`)\n  }\n\n  for (const [alias, specifier] of Object.entries(manifest.catalog)) {\n    if (typeof specifier !== 'string') {\n      throw new InvalidWorkspaceManifestError(`Invalid catalog entry for ${alias}. Expected string, but found: ${typeof specifier}`)\n    }\n  }\n}\n\nexport function assertValidWorkspaceManifestCatalogs (manifest: { packages?: readonly string[], catalogs?: unknown }): asserts manifest is { catalogs?: WorkspaceNamedCatalogs } {\n  if (manifest.catalogs == null) {\n    return\n  }\n\n  if (Array.isArray(manifest.catalogs)) {\n    throw new InvalidWorkspaceManifestError('Expected catalogs field to be an object, but found - array')\n  }\n\n  if (typeof manifest.catalogs !== 'object') {\n    throw new InvalidWorkspaceManifestError(`Expected catalogs field to be an object, but found - ${typeof manifest.catalogs}`)\n  }\n\n  for (const [catalogName, catalog] of Object.entries(manifest.catalogs)) {","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/pnpm/pnpm/blob/6261b7f388016d57ca6b90340342411cd1d0d00f/pnpm11/workspace/workspace-manifest-reader/src/catalogs.ts#L8-L44","documentation":"Every entry in the default `catalog` of pnpm-workspace.yaml must map a package alias to a string version specifier. `assertValidWorkspaceManifestCatalog` iterates `Object.entries(manifest.catalog)` and throws this when an entry's value is not a string — e.g. a number, boolean, or a nested map.","triggerScenarios":"A `catalog` mapping where a value YAML-parses as a non-string: `catalog:\\n  foo: 123` (number), `foo: true` (boolean), or `foo:\\n  version: 1.0.0` (nested object). Triggered whenever `validateWorkspaceManifest` runs on that manifest, i.e. any pnpm command in the workspace.","commonSituations":"Bare semver-like values that YAML coerces to numbers (`1.2` or `1e10` style specifiers), reusing an npm-shrinkwrap/JSON structure with nested `{version, specifier}` objects, or `yes`/`no`/`on`/`off` style values that YAML parses as booleans.","solutions":["Quote every catalog specifier in pnpm-workspace.yaml so YAML keeps it a string: `catalog:\\n  foo: \"1.2\"`","Flatten nested objects to a plain `alias: specifier` string pair","Verify with `pnpm install` after editing to confirm the manifest now parses","Add an editor YAML schema for pnpm-workspace.yaml to catch this as you type"],"exampleFix":"# before\ncatalog:\n  foo:\n    version: 1.2\n\n# after\ncatalog:\n  foo: \"1.2\"","handlingStrategy":"try-catch","validationCode":"const specifiers = Object.values(manifest.catalog ?? {})\nif (specifiers.some((v) => typeof v !== 'string')) {\n  throw new Error('catalog entries must all be string specifiers — quote numeric-looking versions')\n}","typeGuard":"function isValidCatalog (catalog: unknown): boolean {\n  return catalog == null ||\n    (typeof catalog === 'object' && !Array.isArray(catalog) &&\n      Object.entries(catalog).every(([, v]) => typeof v === 'string'))\n}","tryCatchPattern":"try {\n  validateWorkspaceManifest(manifest)\n} catch (err: unknown) {\n  if (util.types.isNativeError(err) && 'code' in err && err.code === 'ERR_PNPM_INVALID_WORKSPACE_CONFIGURATION' && err.message.includes('Invalid catalog entry')) {\n    // surface the alias from the message and fix pnpm-workspace.yaml\n  }\n  throw err\n}","preventionTips":["Quote version specifiers (\"1.2\") to defeat YAML number coercion","Avoid yes/no/on/off values in catalogs","Keep catalog entries flat: alias -> string only"],"tags":["pnpm","workspace","catalog","yaml","type-coercion"],"backgroundTag":"pnpm-workspace-config-validation","analyzedSha":"6261b7f388016d57ca6b90340342411cd1d0d00f","analyzedAt":"2026-08-17T18:30:54.750Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}