affaan-m/ECC · error · Error
plan-canvas request path must be root-relative
Error message
plan-canvas request path must be root-relative
What it means
Thrown by validateRequestPath in scripts/plan-canvas.js when the outbound request path is not a string or does not begin with '/'. This is the first of three guards validating any HTTP path the CLI sends to the loopback canvas server; it enforces that paths are root-relative before URL parsing.
Source
Thrown at scripts/plan-canvas.js:103
function readServerInfo(stateDir) {
try {
return JSON.parse(fs.readFileSync(serverInfoPath(stateDir), 'utf8'));
} catch {
return null;
}
}
function validatePort(port) {
const value = Number(port);
if (!Number.isInteger(value) || value < 0 || value > 65535) {
throw new Error(`invalid plan-canvas server port: ${port}`);
}
return value;
}
function validateRequestPath(requestPath) {
if (typeof requestPath !== 'string' || !requestPath.startsWith('/')) {
throw new Error('plan-canvas request path must be root-relative');
}
const url = new URL(requestPath, `http://${DEFAULT_HOST}`);
if (url.hostname !== DEFAULT_HOST) {
throw new Error('plan-canvas request path must stay on the loopback server');
}
if (!SAFE_REQUEST_PATHS.has(url.pathname) && !SESSION_REPLY_PATH.test(url.pathname)) {
throw new Error(`unsupported plan-canvas request path: ${url.pathname}`);
}
return `${url.pathname}${url.search}`;
}
function requestOptions(port, method, requestPath, headers) {
return {
host: DEFAULT_HOST,
port: validatePort(port),
method,
path: validateRequestPath(requestPath),
agent: false,View on GitHub (pinned to 01e15490f0)
Solutions
- Ensure request paths passed to request() always start with '/', e.g. '/api/sessions'.
- When appending query strings, build them onto a rooted pathname: `/api/await?${params}`.
- If you see this as an end user, it is a bug in plan-canvas.js itself — report it rather than working around it.
Example fix
// before (internal call) request(port, 'GET', 'api/sessions'); // after request(port, 'GET', '/api/sessions');
Defensive patterns
Strategy: validation
Validate before calling
function ensureRootedPath(p) {
if (typeof p !== 'string' || !p.startsWith('/')) {
throw new Error(`Request path must be root-relative: ${String(p)}`);
}
return p;
} Type guard
function isRootedPath(value) {
return typeof value === 'string' && value.startsWith('/');
} Prevention
- Internal callers of request() should always construct paths with a leading slash.
- Keep a single helper that builds request paths so the invariant is enforced in one place.
- End users: report this as a bug; it should not surface through normal CLI usage.
When it happens
Trigger: Calling request() (internal) with a path like 'api/sessions' (no leading slash), an empty string, or a non-string value. This is an internal-API guard — end users normally never set request paths directly; it surfaces via bugs in CLI command code that construct a path without a leading slash.
Common situations: A code change that builds a request path dynamically and omits the leading slash; refactoring that passes a query string or full URL where a pathname is expected.
Related errors
- invalid plan-canvas server port: ${port}
- plan-canvas request path must stay on the loopback server
- unsupported plan-canvas request path: ${url.pathname}
- invalid plan-canvas session key
- Missing value for --target
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/10c0c79e7f857484.
Report an issue: GitHub.