mastra-ai/mastra · error
Path not found in composite skill source: ${path}
Error message
Path not found in composite skill source: ${path} What it means
CompositeVersionedSkillSource.stat routes a virtual path to the underlying per-version skill source via #routePath. When the path does not match any registered version prefix (e.g. a version directory that does not exist), it throws this error instead of delegating. It indicates the requested path is not part of the composite skill's versioned namespace.
Source
Thrown at packages/core/src/workspace/skills/composite-versioned-skill-source.ts:147
}
async stat(path: string): Promise<SkillSourceStat> {
const normalized = this.#normalizePath(path);
// Root directory
if (normalized === '') {
return {
name: '.',
type: 'directory',
size: 0,
createdAt: this.#maxVersionCreatedAt,
modifiedAt: this.#maxVersionCreatedAt,
};
}
const route = this.#routePath(path);
if (!route) {
throw new Error(`Path not found in composite skill source: ${path}`);
}
return route.source.stat(route.subPath);
}
async readFile(path: string): Promise<string | Buffer> {
const route = this.#routePath(path);
if (!route) {
throw new Error(`File not found in composite skill source: ${path}`);
}
return route.source.readFile(route.subPath);
}
async readdir(path: string): Promise<SkillSourceEntry[]> {
const normalized = this.#normalizePath(path);
// Root: list all mounted skill directoriesView on GitHub (pinned to 75dd419e61)
Solutions
- List available paths first (e.g. via list/read of the composite source root) and use an exact existing version prefix in the path.
- Normalize the version segment against registered versions before calling stat (resolve 'latest' or partial versions to a concrete registered version).
- Refresh any cached version listings after skill versions are added/removed, and retry with the corrected path.
Example fix
// before
await source.stat('v3/skill.md'); // v3 not registered -> throws
// after
const entries = await source.list('/');
const path = entries.some(e => e.path === 'v3') ? 'v3/skill.md' : `${entries[0].path}/skill.md`;
await source.stat(path); Defensive patterns
Strategy: try-catch
Validate before calling
async function safeStat(source, path) {
const entries = await source.list('/');
if (!entries.some(e => path === e.path || path.startsWith(e.path + '/'))) {
throw new Error(`Path ${path} not in registered versions: ${entries.map(e => e.path).join(', ')}`);
}
return source.stat(path);
} Try / catch
try {
return await source.stat(path);
} catch (err) {
if (err instanceof Error && err.message.startsWith('Path not found in composite skill source')) {
const versions = await source.list('/');
console.error(`Unknown path ${path}; available: ${versions.map(v => v.path).join(', ')}`);
// resolve to a registered version or surface a user-facing not-found
return null;
}
throw err;
} Prevention
- Refresh cached version listings whenever skill versions are added or removed.
- Never hardcode version strings; resolve 'latest' through the source's own metadata (e.g. maxVersionCreatedAt entries).
- Validate user-supplied version segments against the registered list before composing paths.
- Stat paths only against the same composite source instance that produced them.
When it happens
Trigger: Calling stat()/readFile() with a path whose top-level version segment is not a registered version (e.g. 'v99/file.md' when only v1/v2 exist); a bare path without a version prefix that no route accepts; stale version references after a skill version was removed or renamed.
Common situations: Hardcoded version strings in tooling after versions were pruned; listing paths from one source and stat'ing them against another (different) composite source; typos in version folder names ('v1' vs '1.0'); automation reading latest-version paths cached before a re-index.
Related errors
- [FilesystemStorage] path must be a non-empty relative path.
- ENOENT: no such file or directory: ${path}
- FilesystemSkillsStorage: skill with id ${id} not found
- No versions found for skill ${id}
- Path traversal detected: skill name "${skillName}" escapes s
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/c1e658bf64b132ef.
Report an issue: GitHub.