vercel/ai · error

ACP source.pnpmWorkspaceYaml must not be empty.

Error message

ACP source.pnpmWorkspaceYaml must not be empty.

What it means

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.

Source

Thrown at packages/harness-acp/src/v1/implementation.ts:66

  /^(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-]+)*)?$/;
const PACKAGE_NAME_REGEXP =
  /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/;
const EXECUTABLE_NAME_REGEXP = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
const ENVIRONMENT_VARIABLE_NAME_REGEXP = /^[A-Za-z_][A-Za-z0-9_]*$/;

export function validateACPV1Implementation(
  implementation: ACPImplementation,
): void {
  const { source } = implementation;
  if (source.type === 'npm-locked') {
    if (source.packageJson.length === 0) {
      throw new Error('ACP source.packageJson must not be empty.');
    }
    if (source.pnpmLockYaml.length === 0) {
      throw new Error('ACP source.pnpmLockYaml must not be empty.');
    }
    if (source.pnpmWorkspaceYaml?.length === 0) {
      throw new Error('ACP source.pnpmWorkspaceYaml must not be empty.');
    }
  } else if (source.type === 'npm-simple') {
    validateNpmSimpleSource({ source });
  } else if (source.command.trim().length === 0) {
    throw new Error('ACP source.command must not be empty.');
  }
  if (!EXECUTABLE_NAME_REGEXP.test(implementation.executable)) {
    throw new Error(
      `ACP executable must be a bare command name without a path; received ${JSON.stringify(implementation.executable)}.`,
    );
  }

  validateForwardEnvironment({ forwardEnv: implementation.forwardEnv });
  validateForwardEnvironment({ forwardEnv: implementation.credentialEnv });
  validateEnvironment({ env: implementation.env });
  const forwardedKeys = new Set(implementation.forwardEnv ?? []);
  const credentialKeys = new Set(implementation.credentialEnv ?? []);
  for (const key of credentialKeys) {

View on GitHub (pinned to 69428b1f8b)

Solutions

  1. Provide the actual contents of the repo's pnpm-workspace.yaml in source.pnpmWorkspaceYaml.
  2. If the project has no workspace file, omit the field entirely (undefined) instead of passing an empty string.
  3. Check the code that reads the file — it is swallowing errors and returning '' — and make it throw or skip the field.

Example fix

// before
createACPV1({ source: { type: 'npm-locked', packageJson, pnpmLockYaml, pnpmWorkspaceYaml: fs.readFileSync('pnpm-workspace.yaml', 'utf8') } }); // returns '' if missing
// after
createACPV1({ source: { type: 'npm-locked', packageJson, pnpmLockYaml, pnpmWorkspaceYaml: fs.existsSync('pnpm-workspace.yaml') ? fs.readFileSync('pnpm-workspace.yaml', 'utf8') : undefined } });
Defensive patterns

Strategy: validation

Validate before calling

if (source.type === 'npm-locked' && source.pnpmWorkspaceYaml != null && source.pnpmWorkspaceYaml.length === 0) {
  throw new Error('pnpmWorkspaceYaml must be non-empty or omitted');
}

Type guard

function hasPnpmWorkspaceYaml(source) {
  return source.type !== 'npm-locked' || source.pnpmWorkspaceYaml == null || source.pnpmWorkspaceYaml.length > 0;
}

Try / catch

try {
  const impl = createACPV1(settings);
} catch (err) {
  if (err instanceof Error && err.message.includes('pnpmWorkspaceYaml')) {
    console.error('Fix npm-locked source: provide pnpm-workspace.yaml contents or omit the field');
  }
  throw err;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30). Data as JSON: /api/errors/edc6e0ca7334e77c. Report an issue: GitHub.