mastra-ai/mastra · error
Invalid ${label} path: ${input}
Error message
Invalid ${label} path: ${input} What it means
Thrown by #assertRelativePath when a path supplied to a workspace skill operation is absolute or contains traversal segments ('..'). It normalizes backslashes to forward slashes and rejects any path that starts with '/' or has a '..' segment, returning the cleaned segment list on success.
Source
Thrown at packages/core/src/workspace/skills/workspace-skills.ts:1488
/**
* Join path segments (workspace paths use forward slashes)
*/
#joinPath(...segments: string[]): string {
return segments
.map((seg, i) => (i === 0 ? stripTrailingSlashes(seg) : stripLeadingAndTrailingSlashes(seg)))
.filter(Boolean)
.join('/');
}
/**
* Validate and normalize a relative path to prevent directory traversal.
* Throws if the path contains traversal segments (..) or is absolute.
*/
#assertRelativePath(input: string, label: string): string {
const normalized = input.replace(/\\/g, '/');
const segments = normalized.split('/').filter(seg => Boolean(seg) && seg !== '.');
if (normalized.startsWith('/') || segments.some(seg => seg === '..')) {
throw new Error(`Invalid ${label} path: ${input}`);
}
return segments.join('/');
}
/**
* Get parent path
*/
#getParentPath(path: string): string {
const lastSlash = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\'));
return lastSlash > 0 ? path.substring(0, lastSlash) : '/';
}
}
/**
* Split a path into segments, tolerating both POSIX (`/`) and Windows (`\`)
* separators. Workspace-internal paths use forward slashes, but consumer-supplied
* absolute paths (e.g. via `new Workspace({ skills: [...] })`) may use backslashes
* on Windows.View on GitHub (pinned to 75dd419e61)
Solutions
- Sanitize the input: strip leading slashes and resolve/remove '.' and '..' segments before calling
- Reject absolute or traversal inputs at your app boundary (e.g. return a validation error to the caller)
- Resolve paths against a known base directory and verify the result stays inside it
- Use paths returned by the skills API (discovered references/scripts/assets) instead of free-form input
Example fix
// before
await skills.readSkillFile(skillId, userInputPath);
// after
const rel = userInputPath.replace(/\\/g, '/').split('/').filter(s => s && s !== '.');
if (userInputPath.startsWith('/') || rel.some(s => s === '..')) throw new Error('invalid path');
await skills.readSkillFile(skillId, rel.join('/')); Defensive patterns
Strategy: validation
Validate before calling
function isSafeRelativePath(p: string): boolean {
const norm = p.replace(/\\/g, '/');
if (norm.startsWith('/')) return false;
const segs = norm.split('/').filter(s => s && s !== '.');
return !segs.some(s => s === '..');
} Type guard
function isRelativeSkillPath(p: unknown): p is string {
return typeof p === 'string' && p.length > 0 && isSafeRelativePath(p);
} Try / catch
try {
await skills.readSkillFile(id, path);
} catch (e) {
if (e instanceof Error && /Invalid .* path:/.test(e.message)) {
return { error: 'Path must be relative and cannot contain ..' };
}
throw e;
} Prevention
- Normalize user/model-supplied paths before any skill file API call
- Always resolve against the skill's own directory and verify containment
- Never pass raw absolute paths from clients to skill APIs
- Prefer file handles/IDs returned by discovery APIs over free-form strings
When it happens
Trigger: Calling skill file APIs (read/write/reference/script/asset path operations) with inputs like '/etc/passwd', '../secret.txt', 'C:\\tmp\\file', or any string containing a '..' segment.
Common situations: Model- or user-supplied paths passed straight through to skill file tools; joining a user-controlled relative path onto a skill base dir without sanitizing; Windows-style absolute paths pasted in.
Related errors
- Invalid route path: "${path}". Path cannot contain '..', '?'
- Worker ${label} must stay within the deployed artifact root.
- ${label} escapes workspace
- Path escapes workspace
- Invalid resourceId: ${resourceId}
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/381a9466b5607961.
Report an issue: GitHub.