asgeirtj/system_prompts_leaks · error · Error

[SCHEDULER_MISSING] this DS's dist/ imports 'scheduler' dire

Error message

[SCHEDULER_MISSING] this DS's dist/ imports 'scheduler' directly — usually react-dom leaked into the dist. Check the DS build's externals.

What it means

The design-sync bundler registers an esbuild resolve plugin (bundle.mjs:65) that redirects any import matching /^scheduler(\/|$)/ to a 'scheduler-shim' module whose body is a bare throw (line 115). scheduler is React's internal scheduling dependency, pulled in transitively by react-dom; a properly externalized design-system dist/ never references it. If the dist/ does import scheduler, it means react-dom was inlined into the dist during the DS's own build rather than kept as an external/peer — shipping a second scheduler instance would break concurrent rendering (per the comment at line 63-64). The shim surfaces this as a loud, named error instead of a silent double-scheduler bug.

Source

Thrown at Anthropic/Claude Code/bundled-skills/design-sync/lib/bundle.mjs:115

function tt(o){return o!=null&&typeof o==="object"?(R.isValidElement(o)?(o.type&&o.type.$$typeof)||o.type:o.$$typeof):undefined}
exports.typeOf=tt;
exports.isElement=R.isValidElement;
exports.isValidElementType=function(t){return typeof t==="string"||typeof t==="function"||t===R.Fragment||t===R.Suspense||t===R.StrictMode||t===R.Profiler||(t!=null&&typeof t==="object"&&t.$$typeof!=null)};
exports.isFragment=function(o){return R.isValidElement(o)&&o.type===R.Fragment};
exports.isSuspense=function(o){return R.isValidElement(o)&&o.type===R.Suspense};
exports.isPortal=function(o){return o!=null&&o.$$typeof===PORTAL};
exports.isForwardRef=function(o){return tt(o)===FWD};
exports.isMemo=function(o){return tt(o)===MEMO};
exports.isLazy=function(o){return tt(o)===LAZY};
exports.isContextProvider=exports.isContextConsumer=exports.isProfiler=exports.isStrictMode=function(){return false};
exports.ForwardRef=FWD;exports.Memo=MEMO;exports.Portal=PORTAL;exports.Lazy=LAZY;
exports.Fragment=R.Fragment;exports.Suspense=R.Suspense;exports.StrictMode=R.StrictMode;exports.Profiler=R.Profiler;`,
      loader: 'js',
    }));
    b.onLoad({ filter: /^scheduler-shim$/, namespace: 'shim' }, () => ({
      // A DS dist/ rarely imports scheduler directly — when it does, it
      // means react-dom leaked into the dist. Surface it.
      contents: `throw new Error("[SCHEDULER_MISSING] this DS's dist/ imports 'scheduler' directly — usually react-dom leaked into the dist. Check the DS build's externals.");`,
      loader: 'js',
    }));
  },
};

// Build a resolve plugin from tsconfig compilerOptions.paths. esbuild's
// built-in `tsconfig` option only applies paths to files covered by that
// tsconfig, which the synth entry (in OUT) isn't — so we resolve explicitly.
export function tsconfigPathsPlugin(tsconfigPath) {
  let paths, baseUrl;
  try {
    // Strip // and /* */ comments — tsconfig.json permits them, JSON.parse doesn't.
    const raw = readFileSync(tsconfigPath, 'utf8')
      .replace(/\/\*[\s\S]*?\*\//g, '')
      .replace(/(^|[^:])\/\/.*$/gm, '$1');
    ({ paths, baseUrl = '.' } = JSON.parse(raw).compilerOptions ?? {});
  } catch { return null; }
  if (!paths) return null;

View on GitHub (pinned to 93c999115b)

Solutions

  1. Add 'react-dom' (and 'react', 'scheduler') to the DS build's `external` array in its rollup/webpack/esbuild config, then rebuild the dist.
  2. Ensure the DS package.json lists react-dom (and react) under `peerDependencies`, not `dependencies` — peer deps are never bundled.
  3. Verify the fix: grep the rebuilt dist output for `scheduler` — a correct externalized dist has zero hits.
  4. If the DS is third-party and you cannot rebuild it, contact the DS maintainer or pin to a DS version whose dist is correctly externalized.

Example fix

// before — DS build config (e.g. rollup.config.js) with no externals
export default {
  input: 'src/index.ts',
  output: { file: 'dist/index.js', format: 'esm' },
  // react-dom gets bundled into dist/, pulling in scheduler
};

// after — mark react/react-dom/scheduler as external
export default {
  input: 'src/index.ts',
  output: { file: 'dist/index.js', format: 'esm' },
  external: ['react', 'react-dom', 'scheduler'],
};
// package.json: "peerDependencies": { "react": ">=18", "react-dom": ">=18" }
Defensive patterns

Strategy: validation

Validate before calling

import { readFileSync, readdirSync } from 'node:fs';
import { join } from 'node:path';

// Scan the DS dist for a direct scheduler import BEFORE running
// the design-sync bundle step.
function assertNoSchedulerInDist(distDir) {
  const re = /(?:from\s+['"]scheduler['"]|require\s*\(\s*['"]scheduler['"])/;
  for (const f of readdirSync(distDir)) {
    if (!f.endsWith('.js') && !f.endsWith('.mjs')) continue;
    if (re.test(readFileSync(join(distDir, f), 'utf8'))) {
      throw new Error(`${f} imports scheduler — rebuild DS with react-dom external`);
    }
  }
}

Try / catch

// This is a build-time fail-fast: the throw lives in bundled output.
// Catching it at runtime only masks the real problem (double scheduler).
// Instead, fix the DS externals and rebuild — do NOT wrap in try/catch.

Prevention

When it happens

Trigger: The DS was built without react-dom in its externals, so its bundler inlined react-dom (which imports scheduler) into the dist/. When design-sync's esbuild pipeline bundles that dist/ into a preview, the scheduler import hits the shim and the throw fires during module evaluation of the built preview.

Common situations: DS build config (rollup/webpack/esbuild/vite) missing 'react-dom' in the `external` array. DS package.json listing react-dom under `dependencies` instead of `peerDependencies`, so the bundler treats it as a regular dep to inline. Migrating a DS from a standalone repo into a monorepo and losing the externals config. A DS build that was accidentally run in full-bundle mode (no externals at all).

Related errors


AI-assisted analysis of asgeirtj/system_prompts_leaks@93c999115b (2026-08-13). Data as JSON: /api/errors/dac17e8da0816719. Report an issue: GitHub.