facebook/relay · error · Error

This version of `act` requires a special mock build of Sched

Error message

This version of `act` requires a special mock build of Scheduler.

What it means

Relay's internal act() (used by RelayTestingEnvironment and relay-test-utils) drives React updates synchronously and relies on the mock Scheduler build exposing unstable_flushAllWithoutAsserting. When the real (non-mock) Scheduler is bundled in tests, that function is undefined and act() refuses to run. This is a test-environment configuration error, not a production issue.

Source

Thrown at packages/react-relay/jest-react/internalAct.js:41

const enqueueTask = require('./enqueueTask');
const Scheduler = require('scheduler/unstable_mock');

// The subset of a Promise that React APIs rely on. This resolves a value.
// This doesn't require a return value neither from the handler nor the
// then function.
interface Thenable<out R> {
  then<U>(
    onFulfill: (value: R) => void | Thenable<U> | U,
    onReject: (error: unknown) => void | Thenable<U> | U,
  ): void | Thenable<U>;
}

let actingUpdatesScopeDepth = 0;

function act<T>(scope: () => Thenable<T> | T): Thenable<T> {
  if (Scheduler.unstable_flushAllWithoutAsserting === undefined) {
    throw Error(
      'This version of `act` requires a special mock build of Scheduler.',
    );
  }
  if (setTimeout._isMockFunction !== true) {
    throw Error(
      "This version of `act` requires Jest's timer mocks " +
        '(i.e. jest.useFakeTimers).',
    );
  }

  const previousIsActEnvironment = global.IS_REACT_ACT_ENVIRONMENT;
  const previousActingUpdatesScopeDepth = actingUpdatesScopeDepth;
  actingUpdatesScopeDepth++;
  if (__DEV__ && actingUpdatesScopeDepth === 1) {
    // Because this is not the "real" `act`, we set this to `false` so React
    // knows not to fire `act` warnings.
    global.IS_REACT_ACT_ENVIRONMENT = false;
  }

View on GitHub (pinned to 668b1b85e0)

Solutions

  1. Add/restore the Jest moduleNameMapper that maps 'scheduler' (and scheduler/unstable_mock) to the mock build expected by jest-react
  2. Pin compatible versions of react, relay, and jest-react; check relay's own jest config for the required mappings
  3. If using React's global IS_REACT_ACT_ENVIRONMENT, prefer React.act/test-utils over Relay's internal act for your React version
  4. Clear node_modules and reinstall if duplicated scheduler copies are resolving in the bundle

Example fix

// before (jest.config.js): no scheduler mapping
moduleNameMapper: {}
// after
moduleNameMapper: {
  '^scheduler$': '<rootDir>/node_modules/scheduler/unstable_mock.js',
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before using relay test APIs
if (require('scheduler').unstable_flushAllWithoutAsserting === undefined) {
  throw new Error('Map scheduler to the mock build in jest config before using RelayTestingEnvironment');
}

Try / catch

try {
  testRender(env, <Component />);
} catch (e) {
  if (String(e.message).includes('special mock build of Scheduler')) {
    throw new Error('Jest config missing scheduler mock moduleNameMapper');
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling testRender/commitUpdate or any RelayTestingEnvironment API that invokes internal act() in a Jest project where jest-react's required mock Scheduler isn't resolved — e.g. missing jest scheduler mock mapping, or importing production react-reconciler/scheduler into the test bundle.

Common situations: Upgrading React/Relay without updating the scheduler moduleNameMapper in jest.config, using a monorepo where scheduler resolves to the npm build instead of the mock, or running relay-test-utils with React 18+ where the mock build contract changed.

Related errors


AI-assisted analysis of facebook/relay@668b1b85e0 (2026-09-02). Data as JSON: /api/errors/03c5fb14dafdf5bf. Report an issue: GitHub.