vercel/ai · error
Invalid Pi ${label} name: ${name}
Error message
Invalid Pi ${label} name: ${name} What it means
safePiMetadataSegment validates names used in Pi metadata file paths such as `.pi/skills/<name>/` or `.pi/agents/<name>.md`. It only allows `[A-Za-z0-9._-]` and rejects '.' and '..' to prevent path traversal and shell-sensitive characters. Any name containing slashes, spaces, or other special characters causes this throw.
Source
Thrown at packages/harness-pi/src/pi-utils.ts:78
return output;
}
const serialized = JSON.stringify(output);
return serialized ?? 'null';
}
export function getErrorText(error: unknown): string {
return error instanceof Error ? error.message : String(error);
}
/**
* Validate that a name is safe to use as a filesystem path segment under
* `.pi/skills/<name>/` or `.pi/agents/<name>.md`. Refuses anything that
* could be interpreted as a path traversal or contains shell-sensitive
* characters.
*/
export function safePiMetadataSegment(name: string, label: string): string {
if (!/^[A-Za-z0-9._-]+$/.test(name) || name === '.' || name === '..') {
throw new Error(`Invalid Pi ${label} name: ${name}`);
}
return name;
}
/** Frontmatter renderer for `.pi/skills/<name>/SKILL.md`. */
export function renderPiSkillFile(skill: HarnessV1Skill): string {
return `---\nname: ${skill.name}\ndescription: ${skill.description}\n---\n\n${skill.content}`;
}
View on GitHub (pinned to 69428b1f8b)
Solutions
- Sanitize the name before passing it: lowercase, replace invalid characters with '-', trim.
- Derive the name from the last path segment and strip extensions/slashes.
- Catch the error and surface a clear validation message to the user configuring the skill/agent.
- If you control upstream naming, restrict IDs to the allowed charset at creation time.
Example fix
// before
renderPiSkillFile({ name: 'code-review/assistant', ... });
// after
const safeName = 'code-review/assistant'
.split('/')
.pop()!
.replace(/[^A-Za-z0-9._-]+/g, '-')
.replace(/^\.+$/, '');
renderPiSkillFile({ name: safeName, ... }); Defensive patterns
Strategy: validation
Validate before calling
const PI_NAME_RE = /^[A-Za-z0-9._-]+$/;
function validatePiName(name, label) {
if (!PI_NAME_RE.test(name) || name === '.' || name === '..') {
throw new Error(`Invalid Pi ${label} name: ${name}`);
}
}
validatePiName(skill.name, 'skill'); Try / catch
try {
renderPiSkillFile(skill);
} catch (err) {
if (String(err.message).startsWith('Invalid Pi ')) {
skill.name = slugify(skill.name);
return renderPiSkillFile(skill);
}
throw err;
} Prevention
- Restrict skill/agent IDs to [A-Za-z0-9._-] at creation time
- Slugify names derived from user input, URLs, or file paths
- Never build names by joining path segments
When it happens
Trigger: Calling safePiMetadataSegment(name, label) — directly or via skill/agent rendering functions like renderPiSkillFile — with a name containing '/', '\', spaces, unicode, or equal to '.' or '..'.
Common situations: Deriving a skill name from a URL slug or file path (e.g. 'my/skill'); user-entered skill names with spaces ('my skill'); auto-generated names with colons or slashes from tool IDs; localized names with non-ASCII characters.
Related errors
- Invalid Cline history file name: ${historyFileName}
- Invalid Cline history file name: ${input.historyFileName}
- maxEmbeddingsPerCall must be greater than 0
- Tool approval signature verification failed for approval "${
- ACP harnessId must be a stable kebab-case identifier; receiv
AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30).
Data as JSON: /api/errors/be66c09b28e69da2.
Report an issue: GitHub.