rolldown/rolldown · error · napi::Error

Invalid preset for `generatedCode` option

Error message

Invalid preset for `generatedCode` option: ${s}

What it means

Napi-side validation in normalize_generated_code_option: the `generatedCode.preset` string matched neither 'es5' nor 'es2015'. The value comes from the JS `generatedCode` option object; any other preset string is rejected as invalid.

Solutions

  1. Use preset 'es5' or 'es2015' exactly.
  2. If you need finer control than those presets, drop the `preset` field and set the individual generatedCode flags instead.
  3. Omit `preset` entirely to get defaults.

Example fix

// before
generatedCode: { preset: 'es6' }
// after
generatedCode: { preset: 'es2015' }
Defensive patterns

Strategy: validation

Validate before calling

const VALID_PRESETS = ['es5', 'es2015'];
if (opts.generatedCode?.preset != null && !VALID_PRESETS.includes(opts.generatedCode.preset)) {
  throw new Error(`generatedCode preset must be one of ${VALID_PRESETS.join(', ')}`);
}

Type guard

const isGeneratedCodePreset = (v) =>
  v == null || v === 'es5' || v === 'es2015';

Try / catch

try {
  await build(opts);
} catch (e) {
  if (String(e.message).startsWith('Invalid preset for `generatedCode`')) {
    delete opts.generatedCode.preset; // fall back to per-flag config
  } else throw e;
}

Prevention

When it happens

Trigger: Calling with `generatedCode: { preset: 'es2020' }`, `'es6'`, `'modern'`, or any string other than 'es5'/'es2015'.

Common situations: Assuming arbitrary year presets exist, copying `es6` from other tools' terminology, or typos in the preset name.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of rolldown/rolldown@91b44b9d7b (2026-09-07). Data as JSON: /api/errors/2e1a2b5d71a01d74. Report an issue: GitHub.

Appendix: source

Thrown at crates/rolldown_binding/src/utils/normalize_binding_options.rs:57

use rolldown_plugin::__inner::SharedPluginable;
use rolldown_utils::indexmap::FxIndexMap;
use rolldown_utils::rustc_hash::FxHashMapExt;
use rustc_hash::FxHashMap;
use std::path::PathBuf;
use url::Url;

#[cfg(not(target_family = "wasm"))]
use crate::{options::plugin::ParallelJsPlugin, worker_manager::WorkerManager};
use std::sync::Arc;

fn normalize_generated_code_option(
  value: BindingGeneratedCodeOptions,
) -> napi::Result<GeneratedCodeOptions> {
  let v = match value.preset {
    Some(s) if s == "es5" => GeneratedCodeOptions::es5(),
    Some(s) if s == "es2015" => GeneratedCodeOptions::es2015(),
    Some(s) => {
      return Err(napi::Error::new(
        napi::Status::InvalidArg,
        format!("Invalid preset for `generatedCode` option: {s}"),
      ));
    }
    None => GeneratedCodeOptions::default(),
  };
  Ok(GeneratedCodeOptions { symbols: value.symbols.unwrap_or(v.symbols) })
}

fn normalize_addon_option(
  addon_option: Option<crate::options::AddonOutputOption>,
  name: &'static str,
) -> Option<AddonOutputOption> {
  addon_option.map(move |value| match value {
    // Static string - no JS function call needed
    Either::A(string) => AddonOutputOption::String(Some(string)),
    // Dynamic function
    Either::B(fn_js) => AddonOutputOption::Fn(Arc::new(move |chunk| {

View on GitHub (pinned to 91b44b9d7b)