emotion-js/emotion · error · Error

speedy must be changed before any rules are inserted

Error message

speedy must be changed before any rules are inserted

What it means

Emotion's sheet has a speedy mode (uses CSSOM insertInstead of text nodes) for performance. Once any rule has been inserted (sheet.ctr !== 0), toggling speedy changes how earlier rules were rendered, so in development emotion throws to prevent inconsistent styling.

Source

Thrown at packages/css/src/create-instance.ts:96

  const registeredStyles: string[] = []
  const rawClassName = getRegisteredStyles(
    registered,
    registeredStyles,
    className
  )

  if (registeredStyles.length < 2) {
    return className
  }
  return rawClassName + css(registeredStyles)
}

let createEmotion = (options: Options): Emotion => {
  let cache = createCache(options)

  ;(cache.sheet as CSSStyleSheet).speedy = function (value: boolean) {
    if (isDevelopment && this.ctr !== 0) {
      throw new Error('speedy must be changed before any rules are inserted')
    }
    this.isSpeedy = value
  }

  cache.compat = true

  let css: Emotion['css'] = (
    ...args: (TemplateStringsArray | Interpolation<unknown>)[]
  ) => {
    let serialized = serializeStyles(args, cache.registered, undefined)
    insertStyles(cache, serialized, false)
    return `${cache.key}-${serialized.name}`
  }

  let keyframes: Emotion['keyframes'] = (
    ...args: (TemplateStringsArray | Interpolation<unknown>)[]
  ) => {
    let serialized = serializeStyles(args, cache.registered)

View on GitHub (pinned to b882bcba85)

Solutions

  1. Call sheet.speedy(...) before rendering anything / before the first insert
  2. Set the `speedy` option at createCache/createEmotion time instead: createEmotion({ key, speedy: true })
  3. In tests, create a fresh cache per test and configure speedy before inserting

Example fix

// before
const emotion = createEmotion({ key: 'app' })
render(<App />)
emotion.sheet.speedy(true)
// after
const emotion = createEmotion({ key: 'app', speedy: true })
render(<App />)
Defensive patterns

Strategy: validation

Validate before calling

if (cache.sheet.ctr === 0) {
  cache.sheet.speedy(true);
} else {
  console.warn('speedy can only be toggled before any rules are inserted');
}

Type guard

const canToggleSpeedy = (sheet) => sheet.ctr === 0;

Try / catch

try {
  emotion.sheet.speedy(true);
} catch (e) {
  if (e.message.includes('speedy must be changed')) {
    console.warn('Too late to toggle speedy; recreate the cache instead');
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Calling sheet.speedy(true/false) after at least one style rule was inserted into the cache, typically by calling emotion.sheet.speedy after components have rendered.

Common situations: Trying to disable speedy for testing after app render, calling speedy inside effects after initial paint, or toggling it from devtools/test setup post-render.

Related errors


AI-assisted analysis of emotion-js/emotion@b882bcba85 (2026-09-02). Data as JSON: /api/errors/d8ad71c1195d7966. Report an issue: GitHub.