mastra-ai/mastra · error · Error
Invalid route path: "${path}". Path cannot contain '..', '?'
Error message
Invalid route path: "${path}". Path cannot contain '..', '?', or '#' What it means
normalizeRoutePath validates route path strings used to build client URLs and throws when the path contains '..', '?', or '#'. These characters either enable path traversal or are reserved for query/fragment semantics, so the client rejects them up front instead of producing a malformed or unsafe URL.
Source
Thrown at client-sdks/client-js/src/utils/index.ts:18
import { RequestContext } from '@mastra/core/request-context';
/**
* Normalizes a route path to ensure consistent formatting.
* - Removes leading/trailing whitespace
* - Validates no path traversal (..), query strings (?), or fragments (#)
* - Collapses multiple consecutive slashes
* - Removes trailing slashes
* - Ensures leading slash (unless empty)
*
* @param path - The route path to normalize
* @returns The normalized path (empty string for root paths)
* @throws Error if path contains invalid characters
*/
export function normalizeRoutePath(path: string): string {
let normalized = path.trim();
if (normalized.includes('..') || normalized.includes('?') || normalized.includes('#')) {
throw new Error(`Invalid route path: "${path}". Path cannot contain '..', '?', or '#'`);
}
normalized = normalized.replace(/\/+/g, '/');
if (normalized === '/' || normalized === '') {
return '';
}
if (normalized.endsWith('/')) {
normalized = normalized.slice(0, -1);
}
if (!normalized.startsWith('/')) {
normalized = `/${normalized}`;
}
return normalized;
}
/**
* Checks if a value is a "complex" type that needs JSON serialization for query params.
* Complex types: objects (excluding Date), arrays
* Primitive types: string, number, boolean, null, undefined, DateView on GitHub (pinned to 75dd419e61)
Solutions
- Inspect the path value passed to the client and remove any '?query=...' or '#fragment' parts; pass query params via the client's options instead.
- Sanitize identifiers used in paths (strip or encode '..', '?', '#') before constructing routes.
- If traversal was intended, restructure the call to use the correct base path/resource rather than relative '..' segments.
- Decode once and re-encode properly: use encodeURIComponent on dynamic segments so reserved chars never reach raw path form.
- Check version-specific behavior: if a previously-working path now throws, a validation release tightened normalizeRoutePath.
Example fix
// before
client.getAgent(`/api/agents/${name}?version=2`);
// after
client.getAgent(`/api/agents/${encodeURIComponent(name)}`, { query: { version: 2 } }); Defensive patterns
Strategy: validation
Validate before calling
function isValidRoutePath(path: string): boolean {
const p = path.trim();
return !p.includes('..') && !p.includes('?') && !p.includes('#');
}
if (!isValidRoutePath(userPath)) throw new Error('Rejected route path: ' + userPath); Try / catch
try {
normalizeRoutePath(userPath);
} catch (e) {
if (e.message.startsWith('Invalid route path')) {
console.warn('Sanitizing path', userPath);
userPath = encodeURIComponent(userPath);
} else throw e;
} Prevention
- Always encodeURIComponent dynamic path segments.
- Pass query parameters via request options, never by appending '?' to paths.
- Reject or sanitize '..' in any user-controlled identifiers before building routes.
- Add a unit test that feeds suspect identifiers through route-building helpers.
When it happens
Trigger: Passing a path string containing '..' (traversal segments), '?' (query string), or '#' (fragment) to any client helper that routes through normalizeRoutePath — e.g. building resource URLs from user-supplied agent/workflow/thread names or path segments.
Common situations: Concatenating user input or identifiers that contain query strings into route paths, double-encoding URLs so '?' or '#' survive, or building paths like '/api/agents/' + name where name came from an untrusted source or an old config with '../../other' style overrides.
Related errors
- Worker ${label} must stay within the deployed artifact root.
- ${label} escapes workspace
- Path escapes workspace
- Invalid resourceId: ${resourceId}
- Recording outputPath must be inside ${baseDir}
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/4600de2598452cf6.
Report an issue: GitHub.