can1357/oh-my-pi · error · Error

Project directory is not accessible: ${cwd}

Error message

Project directory is not accessible: ${cwd}

What it means

Before spawning the configured upload command, upload() verifies that the current project directory is enterable (directoryIsEnterableSync) and spawns the process with that directory as cwd. If the directory cannot be entered (missing or lacking permissions) it throws this error rather than spawning the child in an invalid working directory.

Source

Thrown at packages/coding-agent/src/blob-broker/uploaders.ts:98

export function createCommandUploader(template: string): BlobUploader {
	const argvTemplate = splitCommandTemplate(template);
	if (argvTemplate.length === 0) throw new Error("images.urls.command is empty");
	if (!argvTemplate.some(arg => arg.includes("{file}"))) {
		throw new Error("images.urls.command must reference {file}");
	}
	return {
		destination: "command",
		async upload(request: BlobUploadRequest): Promise<BlobPublication> {
			const { bytes, mimeType, extension } = request;
			const file = path.join(os.tmpdir(), `omp-blob-upload-${crypto.randomUUID()}.${extension}`);
			await Bun.write(file, bytes);
			try {
				const argv = argvTemplate.map(arg =>
					arg.replaceAll("{file}", file).replaceAll("{mime}", mimeType).replaceAll("{ext}", extension),
				);
				const cwd = getProjectDir();
				if (!directoryIsEnterableSync(cwd)) {
					throw new Error(`Project directory is not accessible: ${cwd}`);
				}
				const proc = Bun.spawn(argv, { stdin: "ignore", stdout: "pipe", stderr: "pipe", cwd });
				const timeout = setTimeout(() => proc.kill(), UPLOAD_TIMEOUT_MS);
				const [stdout, stderr, exitCode] = await Promise.all([
					new Response(proc.stdout as ReadableStream<Uint8Array>).text(),
					new Response(proc.stderr as ReadableStream<Uint8Array>).text(),
					proc.exited,
				]);
				clearTimeout(timeout);
				if (exitCode !== 0) {
					throw new Error(`${argv[0]} exited with code ${exitCode}: ${stderr.trim().slice(-300)}`);
				}
				const url = extractUploadUrl(stdout);
				if (!url) throw new Error(`${argv[0]} printed no URL on stdout`);
				return { url, destination: "command", bytes: bytes.byteLength };
			} finally {
				await fs.rm(file, { force: true });
			}

View on GitHub (pinned to 9690622007)

Solutions

  1. Restore the project directory or restart the session from an existing directory
  2. Fix directory permissions (chmod/chown so the process user can traverse it)
  3. Re-mount the volume if the directory lives on an unmounted mount
  4. Check you are not running the process from a directory deleted after launch
Defensive patterns

Strategy: try-catch

Validate before calling

import { directoryIsEnterableSync } from "...";
const cwd = getProjectDir();
if (!directoryIsEnterableSync(cwd)) {
	// restore cwd, fix permissions, or fail before attempting uploads
}

Try / catch

try {
	await uploader.upload(req);
} catch (err) {
	if (err instanceof Error && err.message.startsWith("Project directory is not accessible")) {
		// verify project dir exists and is traversable by the process user
	}
	throw err;
}

Prevention

When it happens

Trigger: Calling upload() when the process's project directory has been deleted or renamed after startup; the cwd was removed by a cleanup task; the process lacks read/search permission on the directory (e.g. running as a different user or in a sandbox); NFS/network mount went offline.

Common situations: Running the agent inside a container where the mount was unmounted; deleting the project folder while a session is live; permission tightening (chmod 000) on the working directory; macOS/CI temp-dir cleanup removing the cwd.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/f726df64c484c1f9. Report an issue: GitHub.