n8n-io/n8n · error · UserError

Filesystem error while creating the output directory: ${e in

Error message

Filesystem error while creating the output directory: ${e instanceof Error ? e.message : String(e)}

What it means

The `n8n export:workflow` command wraps filesystem mkdir/lstat errors while preparing the --output directory in a UserError. The original error message (or stringified value) is interpolated. Distinct from the 'must be a directory/file' soft warnings which only log and return.

Source

Thrown at packages/cli/src/commands/export/workflow.ts:109

		if (flags.separate) {
			try {
				if (!flags.output) {
					this.logger.info(
						'You must inform an output directory via --output when using --separate',
					);
					return;
				}

				if (fs.existsSync(flags.output)) {
					if (!fs.lstatSync(flags.output).isDirectory()) {
						this.logger.info('The parameter --output must be a directory');
						return;
					}
				} else {
					fs.mkdirSync(flags.output, { recursive: true });
				}
			} catch (e) {
				throw new UserError(
					`Filesystem error while creating the output directory: ${e instanceof Error ? e.message : String(e)}`,
				);
			}
		} else if (flags.output) {
			if (fs.existsSync(flags.output)) {
				if (fs.lstatSync(flags.output).isDirectory()) {
					this.logger.info('The parameter --output must be a writeable file');
					return;
				}
			}
		}

		const workflows = await Container.get(WorkflowRepository).find({
			where: this.getWhereFilter(flags),
			relations: ['tags', 'shared', 'shared.project'],
		});

		if (workflows.length === 0) {

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Check the embedded cause in the message — fix permissions or choose a writable path.
  2. Ensure the parent directory exists and is writable, or rely on recursive:true by giving a valid absolute path.
  3. If running in Docker, mount a writable volume at the output location.

Example fix

# before
n8n export:workflow --all --output=/readonly/workflows

# after
n8n export:workflow --all --output=./workflows  # writable dir
Defensive patterns

Strategy: validation

Validate before calling

import { access, constants } from 'node:fs/promises';
import { dirname } from 'node:path';
try {
  await access(dirname(outputPath), constants.W_OK);
} catch { /* path not writable: choose another output dir */ }

Type guard

function isOutputDirError(error: unknown): boolean {
  return error instanceof Error && error.message.startsWith('Filesystem error while creating the output directory');
}

Try / catch

try {
  await ExportWorkflow.run(argv);
} catch (e) {
  if (isOutputDirError(e)) { /* parse embedded cause, fix permissions/path, retry */ }
  else throw e;
}

Prevention

When it happens

Trigger: Passing --output pointing at a path the process cannot create or stat: permission denied, read-only filesystem, invalid characters, or a parent that doesn't exist and recursive mkdir fails.

Common situations: Output path on a volume without write permission; container with a read-only mount; path with a typo or missing parent dir; SELinux/AppArmor denying the write.

Related errors


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