{"record":{"id":"edc6e0ca7334e77c","repo":"vercel/ai","slug":"acp-source-pnpmworkspaceyaml-must-not-be-empty","errorCode":null,"errorMessage":"ACP source.pnpmWorkspaceYaml must not be empty.","messagePattern":"ACP source\\.pnpmWorkspaceYaml must not be empty\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/harness-acp/src/v1/implementation.ts","lineNumber":66,"sourceCode":"  /^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?$/;\nconst PACKAGE_NAME_REGEXP =\n  /^(?:@[a-z0-9][a-z0-9._-]*\\/)?[a-z0-9][a-z0-9._-]*$/;\nconst EXECUTABLE_NAME_REGEXP = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;\nconst ENVIRONMENT_VARIABLE_NAME_REGEXP = /^[A-Za-z_][A-Za-z0-9_]*$/;\n\nexport function validateACPV1Implementation(\n  implementation: ACPImplementation,\n): void {\n  const { source } = implementation;\n  if (source.type === 'npm-locked') {\n    if (source.packageJson.length === 0) {\n      throw new Error('ACP source.packageJson must not be empty.');\n    }\n    if (source.pnpmLockYaml.length === 0) {\n      throw new Error('ACP source.pnpmLockYaml must not be empty.');\n    }\n    if (source.pnpmWorkspaceYaml?.length === 0) {\n      throw new Error('ACP source.pnpmWorkspaceYaml must not be empty.');\n    }\n  } else if (source.type === 'npm-simple') {\n    validateNpmSimpleSource({ source });\n  } else if (source.command.trim().length === 0) {\n    throw new Error('ACP source.command must not be empty.');\n  }\n  if (!EXECUTABLE_NAME_REGEXP.test(implementation.executable)) {\n    throw new Error(\n      `ACP executable must be a bare command name without a path; received ${JSON.stringify(implementation.executable)}.`,\n    );\n  }\n\n  validateForwardEnvironment({ forwardEnv: implementation.forwardEnv });\n  validateForwardEnvironment({ forwardEnv: implementation.credentialEnv });\n  validateEnvironment({ env: implementation.env });\n  const forwardedKeys = new Set(implementation.forwardEnv ?? []);\n  const credentialKeys = new Set(implementation.credentialEnv ?? []);\n  for (const key of credentialKeys) {","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/vercel/ai/blob/69428b1f8b037e4d118fb4853428d5c4e620493c/packages/harness-acp/src/v1/implementation.ts#L48-L84","documentation":"createACPV1 validates that an 'npm-locked' ACP source carries a non-empty pnpmWorkspaceYaml string. The npm-locked source type reproduces a workspace install from checked-in pnpm-lock.yaml and pnpm-workspace.yaml files, so an empty pnpm-workspace.yaml means the launch cannot faithfully reconstruct the dependency graph. This guard fails fast at construction instead of at install time.","triggerScenarios":"Calling createACPV1 with source.type === 'npm-locked' and source.pnpmWorkspaceYaml set to an empty string ('' or ' '). Note: undefined/null is allowed (the check is ?.length === 0), only explicitly-empty strings throw.","commonSituations":"Loading pnpm-workspace.yaml with a read that returns '' on failure (e.g. fs.readFileSync defaulting), building config programmatically from environment variables that are unset-to-empty, or copying config from a repo without a pnpm-workspace.yaml.","solutions":["Provide the actual contents of the repo's pnpm-workspace.yaml in source.pnpmWorkspaceYaml.","If the project has no workspace file, omit the field entirely (undefined) instead of passing an empty string.","Check the code that reads the file — it is swallowing errors and returning '' — and make it throw or skip the field."],"exampleFix":"// before\ncreateACPV1({ source: { type: 'npm-locked', packageJson, pnpmLockYaml, pnpmWorkspaceYaml: fs.readFileSync('pnpm-workspace.yaml', 'utf8') } }); // returns '' if missing\n// after\ncreateACPV1({ source: { type: 'npm-locked', packageJson, pnpmLockYaml, pnpmWorkspaceYaml: fs.existsSync('pnpm-workspace.yaml') ? fs.readFileSync('pnpm-workspace.yaml', 'utf8') : undefined } });","handlingStrategy":"validation","validationCode":"if (source.type === 'npm-locked' && source.pnpmWorkspaceYaml != null && source.pnpmWorkspaceYaml.length === 0) {\n  throw new Error('pnpmWorkspaceYaml must be non-empty or omitted');\n}","typeGuard":"function hasPnpmWorkspaceYaml(source) {\n  return source.type !== 'npm-locked' || source.pnpmWorkspaceYaml == null || source.pnpmWorkspaceYaml.length > 0;\n}","tryCatchPattern":"try {\n  const impl = createACPV1(settings);\n} catch (err) {\n  if (err instanceof Error && err.message.includes('pnpmWorkspaceYaml')) {\n    console.error('Fix npm-locked source: provide pnpm-workspace.yaml contents or omit the field');\n  }\n  throw err;\n}","preventionTips":["Only set pnpmWorkspaceYaml when the file exists and was read successfully","Treat empty-string file reads as errors in your config loader","Omit the field (undefined) when the project has no workspace file"],"tags":["configuration","validation","npm"],"backgroundTag":"invalid-config-value","analyzedSha":"69428b1f8b037e4d118fb4853428d5c4e620493c","analyzedAt":"2026-08-30T12:32:21.016Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}