different-ai/openwork · error · ApiError

invalid_path

invalid_path

Error message

Path must be absolute

What it means

assertAbsolute validates that a supplied filesystem path is absolute before the server resolves it; relative paths (or empty strings) raise this 400 ApiError with code invalid_path. The server API never interprets paths relative to its own CWD.

Source

Thrown at apps/server/src/paths.ts:7

import { realpath } from "node:fs/promises";
import { isAbsolute, resolve, sep } from "node:path";
import { ApiError } from "./errors.js";

export function assertAbsolute(path: string): void {
  if (!isAbsolute(path)) {
    throw new ApiError(400, "invalid_path", "Path must be absolute");
  }
}

export async function resolveWithinRoot(root: string, ...segments: string[]): Promise<string> {
  const resolvedRoot = await realpath(root);
  const candidate = resolve(resolvedRoot, ...segments);
  const resolvedCandidate = await realpath(candidate).catch(() => candidate);
  if (resolvedCandidate === resolvedRoot) return candidate;
  if (!resolvedCandidate.startsWith(resolvedRoot + sep)) {
    throw new ApiError(400, "path_escape", "Path escapes workspace root");
  }
  return candidate;
}

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Convert the path to absolute on the caller side (path.resolve / path.join with the workspace root) before sending.
  2. Prefix with the workspace root directory you registered with the server.
  3. Trim/handle empty strings before calling.
  4. In tests, build absolute paths from a tmpdir instead of fixtures.

Example fix

// before
await api.filePath({ path: "src/index.ts" });
// after
import { resolve } from "node:path";
await api.filePath({ path: resolve(workspaceRoot, "src/index.ts") });
Defensive patterns

Strategy: validation

Validate before calling

import { isAbsolute, resolve } from "node:path";
function toAbsolute(p: string, workspaceRoot: string): string {
  const abs = resolve(workspaceRoot, p);
  if (!isAbsolute(abs)) throw new Error(`Path must be absolute: ${p}`);
  return abs;
}

Type guard

function isAbsolutePath(p: string): boolean {
  return typeof p === "string" && p.length > 0 && isAbsolute(p);
}

Try / catch

import { ApiError } from "./errors.js";
try {
  assertAbsolute(userPath);
} catch (err) {
  if (err instanceof ApiError && err.code === "invalid_path") {
    throw new ApiError(400, "invalid_path", `Provide an absolute path, got: ${userPath}`);
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling filePath or any path-taking API with a relative path like "src/foo.ts" or "./notes.txt", an empty path, or a path built from a URL-encoded relative segment.

Common situations: Clients assuming server-side CWD resolution; passing workspace-relative paths from UI code; forgetting path.resolve on the client; tests reusing relative fixtures.

Related errors


AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01). Data as JSON: /api/errors/9701844604664e2c. Report an issue: GitHub.