denoland/deno · error · Error

'create' or 'createNew' options require 'write' or 'append'

Error message

'create' or 'createNew' options require 'write' or 'append' to be true

What it means

Final rule of checkOpenOptions for Deno.open/openSync: create/createNew only make sense when the file will also be written or appended to. Opening with create: true (or createNew: true) but neither write nor append would create a file that can never receive bytes, so a plain Error is thrown. This mirrors Node's validation for the same flag combinations.

Source

Thrown at ext/fs/30_fs.js:817

    ).length === 0
  ) {
    throw new Error(
      "'options' requires at least one option to be true",
    );
  }

  if (options.truncate && !options.write) {
    throw new Error(
      "'truncate' option requires 'write' to be true",
    );
  }

  const createOrCreateNewWithoutWriteOrAppend =
    (options.create || options.createNew) &&
    !(options.write || options.append);

  if (createOrCreateNewWithoutWriteOrAppend) {
    throw new Error(
      "'create' or 'createNew' options require 'write' or 'append' to be true",
    );
  }
}

function readFileSync(path) {
  return op_fs_read_file_sync(pathFromURL(path));
}

async function readFile(path, options) {
  let cancelRid;
  let abortHandler;
  if (options?.signal) {
    options.signal.throwIfAborted();
    cancelRid = createCancelHandle();
    abortHandler = () => core.tryClose(cancelRid);
    options.signal[abortSignal.add](abortHandler);
  }

View on GitHub (pinned to 89f33cbef2)

Solutions

  1. Pair create with write: { create: true, write: true } (or append: true)
  2. For touch-like creation with content, use Deno.writeTextFile with create: true
  3. For Node-'w' behavior use { write: true, create: true, truncate: true }; for fail-if-exists use createNew

Example fix

// before
await Deno.open("/tmp/x", { create: true }); // Error

// after
await Deno.open("/tmp/x", { create: true, write: true });
Defensive patterns

Strategy: validation

Validate before calling

function normalizeOpenOptions(o) {
  if ((o.create || o.createNew) && !(o.write || o.append)) o = { ...o, write: true };
  return o;
}
await Deno.open(path, normalizeOpenOptions(options));

Type guard

function areCreateOptionsValid(o: {
  create?: boolean;
  createNew?: boolean;
  write?: boolean;
  append?: boolean;
}): boolean {
  return !((o.create || o.createNew) && !(o.write || o.append));
}

Try / catch

try {
  file = await Deno.open(path, options);
} catch (err) {
  if (err instanceof Error && err.message === "'create' or 'createNew' options require 'write' or 'append' to be true") {
    file = await Deno.open(path, { ...options, write: true });
  } else throw err;
}

Prevention

When it happens

Trigger: Deno.open(path, { create: true }) or Deno.openSync(path, { createNew: true }) without write: true or append: true.

Common situations: Expecting create to work like touch; porting Node flag 'wx'/'ax' partially; constructing options from conditionals where the write flag is dropped when a file already exists.

Related errors


AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16). Data as JSON: /api/errors/745f9e7c17dad73e. Report an issue: GitHub.