denoland/deno · error · ERR_INCOMPATIBLE_OPTION_PAIR

ERR_INCOMPATIBLE_OPTION_PAIR

ERR_INCOMPATIBLE_OPTION_PAIR

Error message

Option "dereference" cannot be used in combination with option "verbatimSymlinks"

What it means

The option normalizer for fs.cp validates each boolean flag and then rejects the combination dereference: true with verbatimSymlinks: true using ERR_INCOMPATIBLE_OPTION_PAIR. The flags give opposite instructions — dereference copies the targets' contents, verbatimSymlinks recreates the links as-is without resolving them — so no single copy can satisfy both.

Source

Thrown at ext/node/polyfills/internal/fs/utils.mjs:1008

  recursive: false,
};

/** @type {(options: CopyOptionsBase | undefined) => CopyOptionsBase} */
export const validateCpOptions = hideStackFrames((options) => {
  if (options === undefined) {
    return { ...defaultCpOptions };
  }
  validateObject(options, "options");
  options = { ...defaultCpOptions, ...options };
  validateBoolean(options.dereference, "options.dereference");
  validateBoolean(options.errorOnExist, "options.errorOnExist");
  validateBoolean(options.force, "options.force");
  validateBoolean(options.preserveTimestamps, "options.preserveTimestamps");
  validateBoolean(options.recursive, "options.recursive");
  validateBoolean(options.verbatimSymlinks, "options.verbatimSymlinks");
  options.mode = getValidMode(options.mode, "copyFile");
  if (options.dereference === true && options.verbatimSymlinks === true) {
    throw new ERR_INCOMPATIBLE_OPTION_PAIR("dereference", "verbatimSymlinks");
  }
  if (options.filter !== undefined) {
    validateFunction(options.filter, "options.filter");
  }
  return options;
});

/**
 * @typedef {{
 *   force: boolean;
 *   recursive?: boolean;
 *   retryDelay?: number;
 *   maxRetries?: number;
 * }} RmOptions
 */

/**
 * @typedef {(err: Error | false | null, options?: RmOptions) => void} RmOptionsCallback

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Pick one strategy: dereference to copy contents, verbatimSymlinks to recreate links verbatim — enable exactly one.
  2. Delete the other key when merging presets instead of leaving stale values.
  3. Validate the merged options object with a two-line check before calling fs.cp.

Example fix

// before
await fs.promises.cp(src, dest, { recursive: true, dereference: true, verbatimSymlinks: true }); // throws

// after — copy link targets' contents
await fs.promises.cp(src, dest, { recursive: true, dereference: true });
// or — recreate symlinks verbatim
await fs.promises.cp(src, dest, { recursive: true, verbatimSymlinks: true });
Defensive patterns

Strategy: validation

Validate before calling

if (opts?.dereference === true && opts?.verbatimSymlinks === true) {
  throw new Error('cp options are contradictory: dereference copies targets, verbatimSymlinks preserves links — pick one');
}

Prevention

When it happens

Trigger: fs.cp(src, dest, { recursive: true, dereference: true, verbatimSymlinks: true }); merging two presets that each enable one flag; layered config (defaults plus user overrides) where both end up true.

Common situations: Deploy/copy scripts accumulating options from CLI flags, config files and presets; combining a 'follow links' preset with a 'preserve links' preset; copying node_modules or build trees where either strategy is wanted but never both.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/74231c410057d497. Report an issue: GitHub.