Hmbown/CodeWhale · error · Error

(): unknown mode ; expected one of

Error message

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

What it means

Thrown by the prelude's `slotMode` helper in vm.rs when `task()`/`parallel()`/`pipeline()` receive an `opts.mode` value that is not one of the allowed SLOT_MODES (e.g. "settled", "fail-fast", "partial"). This fail-loud validation prevents typos like "failfast" from silently falling back to default behavior and dropping slots the author believed were fatal.

Solutions

  1. Use one of the documented SLOT_MODES exactly: check the list in the error message (joined after 'expected one of').
  2. Fix casing/spelling — modes are exact string matches (e.g. "fail-fast", not "failfast").
  3. Omit `mode` entirely if you want the default "settled" behavior (mode === undefined falls back to it).
  4. Ensure `mode` is a string, not a boolean/number.

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"]; // per docs/error message
function assertMode(mode) {
  if (mode !== undefined && !SLOT_MODES.includes(mode)) {
    throw new Error(`unknown mode ${JSON.stringify(mode)}; expected one of ${SLOT_MODES.join(", ")}`);
  }
}

Type guard

function isSlotMode(v) {
  return v === undefined || (typeof v === 'string' && ["settled", "fail-fast", "partial"].includes(v));
}

Try / catch

try {
  await parallel(thunks, { mode });
} catch (e) {
  if (e.message.includes('unknown mode')) {
    console.error(`bad mode literal ${opts.mode}; use one listed in the error`);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling `parallel(thunks, { mode: "failfast" })`, `pipeline(items, { stages: [...], mode: "Fail-Fast" })`, or any opts object whose `mode` is a misspelled/case-wrong/unsupported string; also passing mode as a non-string (e.g. true or 1).

Common situations: Typo or wrong casing in the mode literal; inventing a mode name that does not exist; copying an option from another library's fan-out API; passing a non-string value.

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@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/f139953b56300c78. Report an issue: GitHub.

Appendix: source

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

      } 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 73e0f67d83)