vercel/turborepo · error · ConvertError
pnpm-workspace_parse_error
pnpm-workspace_parse_error
Error message
failed to parse ${workspaceFile} What it means
Thrown by getYamlWorkspaces() in turbo-workspaces when pnpm-workspace.yaml (or aube-workspace.yaml, which shares the code path) exists but yaml.load throws - i.e. the file is syntactically invalid YAML. ConvertError type "pnpm-workspace_parse_error" with the full file path in the message. Subtlety: it is thrown only on YAML syntax errors - a file that parses but has the wrong shape (packages not an array, or missing) silently yields [] and no error. Reached from pnpm/aube read(); detect() passes as soon as the file exists, so the failure appears after detection, mid-read of an otherwise recognized project.
Source
Thrown at packages/turbo-workspaces/src/utils.ts:373
workspaceFileName
}: {
workspaceRoot: string;
workspaceFileName: string;
}): Array<string> {
const workspaceFile = path.join(workspaceRoot, workspaceFileName);
if (existsSync(workspaceFile)) {
try {
const workspaceConfig = yaml.load(readFileSync(workspaceFile, "utf8"));
// validate it's the type we expect
if (
workspaceConfig instanceof Object &&
"packages" in workspaceConfig &&
Array.isArray(workspaceConfig.packages)
) {
return workspaceConfig.packages as Array<string>;
}
} catch (err) {
throw new ConvertError(`failed to parse ${workspaceFile}`, {
type: "pnpm-workspace_parse_error"
});
}
}
return [];
}
function expandPaths({
root,
lockFile,
workspaceConfig
}: {
root: string;
lockFile: string;
workspaceConfig?: string;
}) {
const fromRoot = (p: string) => path.join(root, p);View on GitHub (pinned to 9f94a7d215)
Solutions
- Get the precise line from a YAML parser: `node -e "require('js-yaml').load(require('fs').readFileSync('pnpm-workspace.yaml','utf8'))"` - js-yaml prints position info that the ConvertError deliberately omits
- Fix the syntax: use spaces (never tabs) for indentation, keep `packages:` as a YAML list of quoted globs, remove conflict markers and duplicate keys
- Verify the shape is `packages:\n - \"apps/*\"` (array of strings) - remember a non-array packages value will not throw but silently disables workspace discovery
- Validate the file in CI (parse it with js-yaml and assert Array.isArray(cfg.packages)) before running migrations
Example fix
# before - pnpm-workspace.yaml that throws (alias star, tab indent) packages: apps/* packages: - apps/* # after - valid YAML, quoted globs, space indent packages: - "apps/*" - "packages/*"
Defensive patterns
Strategy: validation
Validate before calling
import { readFileSync, existsSync } from "node:fs";
import path from "node:path";
import yaml from "js-yaml";
const wsPath = path.join(root, "pnpm-workspace.yaml");
if (existsSync(wsPath)) {
const cfg = yaml.load(readFileSync(wsPath, "utf8")) as { packages?: unknown };
if (!Array.isArray(cfg?.packages)) {
throw new Error(`${wsPath}: 'packages' must be an array of globs`);
}
}
const details = await getWorkspaceDetails({ root }); Type guard
import { ConvertError } from "turbo-workspaces";
function isPnpmWorkspaceParseError(err: unknown): err is ConvertError {
return err instanceof ConvertError && err.type === "pnpm-workspace_parse_error";
} Try / catch
try {
const details = await getWorkspaceDetails({ root });
} catch (err) {
if (err instanceof ConvertError && err.type === "pnpm-workspace_parse_error") {
try {
yaml.load(readFileSync(path.join(root, "pnpm-workspace.yaml"), "utf8"));
} catch (e) {
console.error(`Fix pnpm-workspace.yaml: ${(e as Error).message}`); // includes line numbers
}
process.exit(1);
} else throw err;
} Prevention
- Use spaces (never tabs) in pnpm-workspace.yaml
- Write globs as quoted list items under packages: ("apps/*"), never as a bare `packages: apps/*` scalar
- Add a CI check that js-yaml-parses pnpm-workspace.yaml and asserts Array.isArray(packages)
- Resolve git merge conflicts fully - conflict markers are valid-looking but fatal YAML
When it happens
Trigger: pnpm-workspace.yaml with tabs used for indentation; an unquoted asterisk scalar such as `packages: apps/*` (YAML reads `*` as an alias reference and js-yaml throws 'unknown alias'); duplicate keys; merge-conflict markers left after a git merge; malformed indent after hand-editing the catalog/workspace list.
Common situations: Copying a workspace glob from docs into the wrong YAML shape (`packages: apps/*` instead of a list under packages); tabs inserted by a configured-for-Tabs editor; merge conflicts in frequently-edited pnpm-workspace.yaml (catalog entries) resolved with markers still present; renames from pnpm-workspace.yml or partial writes after a crashed save.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- package_manager-unexpected
- New workspace root detected - unexpected pnpm-workspace.yaml
- package_manager-unexpected
- package_manager-unexpected
- package_manager-unexpected
AI-assisted analysis of vercel/turborepo@9f94a7d215 (2026-08-16).
Data as JSON: /api/errors/77b87b70ed42a12b.
Report an issue: GitHub.