vercel/ai · error

ACP source.pnpmLockYaml must not be empty.

Error message

ACP source.pnpmLockYaml must not be empty.

What it means

validateACPV1Implementation also requires that a 'npm-locked' source includes non-empty pnpmLockYaml; the lockfile is needed for reproducible installs of the agent package. An empty string indicates the lockfile contents were not provided.

Source

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

}

const EXACT_SEMVER_REGEXP =
  /^(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 });

View on GitHub (pinned to 69428b1f8b)

Solutions

  1. Populate source.pnpmLockYaml with the actual pnpm-lock.yaml contents.
  2. Fix the packaging/read step that produced an empty string (check file path and error handling).
  3. Switch to source.type 'npm-simple' with validateNpmSimpleSource-compliant fields if a lockfile is genuinely unavailable.

Example fix

// before
const pnpmLockYaml = await maybeRead('pnpm-lock.yaml'); // '' on failure
createACPV1({ implementation: { source: { type: 'npm-locked', packageJson, pnpmLockYaml } } });
// after
const pnpmLockYaml = await fs.readFile('pnpm-lock.yaml', 'utf8'); // throws if missing
if (pnpmLockYaml.length === 0) throw new Error('pnpm-lock.yaml is empty');
Defensive patterns

Strategy: validation

Validate before calling

if (source.type === 'npm-locked' && source.pnpmLockYaml.length === 0) {
  throw new Error('source.pnpmLockYaml is empty; load pnpm-lock.yaml contents before createACPV1');
}

Try / catch

try {
  createACPV1({ implementation });
} catch (error) {
  if (error instanceof Error && error.message.includes('pnpmLockYaml must not be empty')) {
    throw new Error('Implementation packaging failed: pnpm-lock.yaml was not embedded');
  }
  throw error;
}

Prevention

When it happens

Trigger: Calling createACPV1 with a 'npm-locked' implementation whose pnpmLockYaml is '' — e.g. pnpm-lock.yaml not bundled, a read failure returning '', or the field forgotten in the config.

Common situations: Packaging scripts that copy package.json but forget pnpm-lock.yaml; monorepo configs pointing at the wrong lockfile path; CI artifact assembly missing the lockfile.

Related errors


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