Hmbown/CodeWhale · error · Error

fn + "(): unknown mode " + JSON.stringify(opts.mode) + "…

Error message

fn + "(): unknown mode " + JSON.stringify(opts.mode) + "; expected one of " + SLOT_MODES.join(", ")

What it means

slotMode() validates the opts.mode given to parallel()/pipeline() against the allowed SLOT_MODES. An options object with a mode outside that set throws this error naming the function, the bad mode, and the valid modes. Missing mode or a non-object opts defaults to "settled" without error.

Solutions

  1. Use exactly one of the listed modes; per the code paths these are 'settled', 'fail-fast', and 'partial'.
  2. Fix casing/spelling: 'fail-fast' is hyphenated and lowercase.
  3. Omit the mode option entirely to get the default 'settled' behavior.
  4. Log JSON.stringify(opts.mode) at the call site to see the actual value being passed.

Example fix

// before
await parallel(thunks, { mode: 'failfast' });
// after
await parallel(thunks, { mode: 'fail-fast' });
Defensive patterns

Strategy: validation

Validate before calling

const SLOT_MODES = ['settled', 'fail-fast', 'partial'];
function validSlotMode(opts) {
  return opts == null || typeof opts !== 'object' || opts.mode === undefined
    || SLOT_MODES.includes(opts.mode);
}

Type guard

const isSlotOpts = (o) => o == null || (typeof o === 'object' && (o.mode === undefined || ['settled','fail-fast','partial'].includes(o.mode)));

Try / catch

try {
  await parallel(thunks, opts);
} catch (e) {
  if (e.message.includes('unknown mode')) {
    await parallel(thunks); // fall back to default 'settled'
  } else throw e;
}

Prevention

When it happens

Trigger: Calling parallel(thunks, { mode: '...' }) or pipeline(items, { mode: '...' }) with a mode string not in SLOT_MODES (e.g. 'abort', 'failfast', 'Fail-Fast', or a non-string value like true or 1).

Common situations: Typos ('failfast' vs 'fail-fast'), assuming other modes exist, casing mistakes, or passing a boolean where the mode string was expected.

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 Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/1ef3c77f9758ccac. Report an issue: GitHub.

Appendix: source

Thrown at crates/workflow-js/src/vm.rs:1333

      } catch (_) {
        // A frozen error keeps whatever it has; the log line still names it.
      }
    }
    return err;
  };

  const SLOT_MODES = ["settled", "fail-fast", "partial"];
  // `settled` is the default and is exactly today's behavior: a non-fatal
  // slot failure resolves to `null` so an author need not handle every error.
  // An unrecognized mode throws rather than silently falling back — a typo
  // like `mode: "failfast"` used to read as `settled` and quietly keep
  // dropping slots the author believed were now fatal.
  const slotMode = (fn, opts) => {
    if (opts === null || typeof opts !== "object" || opts.mode === undefined) {
      return "settled";
    }
    if (SLOT_MODES.indexOf(opts.mode) === -1) {
      throw new Error(
        fn + "(): unknown mode " + JSON.stringify(opts.mode) +
        "; expected one of " + SLOT_MODES.join(", ")
      );
    }
    return opts.mode;
  };

  // The failure ledger for one fan-out, attached to the resolved array as a
  // non-enumerable `errors` property. Non-enumerable and non-index, so the
  // array's contents, length, and JSON encoding are byte-identical to before:
  // `results.filter(Boolean)` still works, and a script that wants to know
  // WHY a slot is null can now ask instead of guessing.
  const attachSlotErrors = (results, errors) => {
    errors.sort((a, b) => a.index - b.index);
    Object.defineProperty(results, "errors", {
      value: Object.freeze(errors.map((entry) => Object.freeze(entry))),
      enumerable: false,
      configurable: false,

View on GitHub (pinned to 433685b202)