n8n-io/n8n · error · DaytonaFileNotFoundError

File not found: ${path}

Error message

File not found: ${path}

What it means

DaytonaFilesystem.stat() delegates to the Daytona SDK's getFileDetails(). When the SDK rejects with a 404 (detected by isDaytona404: an Error with `statusCode === 404`), the adapter rethrows it as a typed DaytonaFileNotFoundError whose message is `File not found: <path>`. This lets callers distinguish a genuinely missing file from transport/auth/provider errors.

Source

Thrown at packages/@n8n/agents/src/workspace/filesystem/daytona-filesystem.ts:161

				return true;
			} catch (error) {
				// A genuine 404 means the file is absent. Sandbox/provider errors (e.g. a
				// stopped sandbox) must bubble up so withFilesystem() can recover instead of
				// silently reporting the file as missing.
				if (isDaytona404(error)) return false;
				throw error;
			}
		}, options?.abortSignal);
	}

	async stat(path: string, options?: AbortableOptions): Promise<FileStat> {
		return await this.withFs(async (fs) => {
			let info;
			try {
				info = await fs.getFileDetails(path);
			} catch (error: unknown) {
				if (isDaytona404(error)) {
					throw new DaytonaFileNotFoundError(path);
				}
				throw error;
			}
			return {
				name: info.name ?? path.split('/').pop() ?? '',
				path,
				type: info.isDir ? 'directory' : 'file',
				size: info.size ?? 0,
				createdAt: new Date(info.modTime ?? 0),
				modifiedAt: new Date(info.modTime ?? 0),
			};
		}, options?.abortSignal);
	}
}

class DaytonaFileNotFoundError extends Error {
	constructor(path: string) {
		super(`File not found: ${path}`);

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Verify the absolute path and casing against the sandbox working directory before calling stat.
  2. If existence is uncertain, list the parent first or treat the not-found error as a soft 'no'.
  3. Catch by error.name === 'DaytonaFileNotFoundError' and surface a clean not-found to the user instead of a raw stack.

Example fix

// before
const info = await fs.stat(maybePath);

// after
try {
  return await fs.stat(maybePath);
} catch (e) {
  if (e instanceof Error && e.name === 'DaytonaFileNotFoundError') return null;
  throw e;
}
Defensive patterns

Strategy: try-catch

Type guard

function isDaytonaFileNotFound(e: unknown): boolean {
  return e instanceof Error && e.name === 'DaytonaFileNotFoundError';
}

Try / catch

try {
  return await fs.stat(path);
} catch (e) {
  if (isDaytonaFileNotFound(e)) return null; // treat as 'not found'
  throw e;
}

Prevention

When it happens

Trigger: Calling stat() (or any built-in tool routed through it) on a path that does not exist in the Daytona sandbox: a typo, a wrong relative path resolved against an unexpected cwd, a case mismatch on a case-sensitive FS, or a file deleted between a list and a stat.

Common situations: An agent tool call references a path it assumed existed; the working directory differed from what the agent expected; another process removed the file mid-workflow; cross-platform path separators (`\` vs `/`).

Related errors


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/b52087029cb039b2. Report an issue: GitHub.