emotion-js/emotion · error · Error

[ThemeProvider] Please return an object from your theme func

Error message

[ThemeProvider] Please return an object from your theme function, i.e. theme={() => ({})}!

What it means

@emotion/react's ThemeProvider getTheme() validates that the resolved theme is a non-null, non-array object. When the theme prop is a function, the function's return value (mergedTheme) is checked; if the function returns null, undefined, a primitive, or an array, this error is thrown in development. It exists because downstream emotion code destructures and spreads the theme and would otherwise fail with confusing errors.

Source

Thrown at packages/react/src/theming.tsx:42

if (isDevelopment) {
  ThemeContext.displayName = 'EmotionThemeContext'
}

export const useTheme = () => React.useContext(ThemeContext)

const getTheme = (
  outerTheme: Theme,
  theme: Partial<Theme> | ((theme: Theme) => Theme)
): Theme => {
  if (typeof theme === 'function') {
    const mergedTheme = theme(outerTheme)
    if (
      isDevelopment &&
      (mergedTheme == null ||
        typeof mergedTheme !== 'object' ||
        Array.isArray(mergedTheme))
    ) {
      throw new Error(
        '[ThemeProvider] Please return an object from your theme function, i.e. theme={() => ({})}!'
      )
    }
    return mergedTheme
  }
  if (
    isDevelopment &&
    (theme == null || typeof theme !== 'object' || Array.isArray(theme))
  ) {
    throw new Error(
      '[ThemeProvider] Please make your theme prop a plain object'
    )
  }

  return { ...outerTheme, ...theme }
}

let createCacheWithTheme = /* #__PURE__ */ weakMemoize((outerTheme: Theme) => {

View on GitHub (pinned to b882bcba85)

Solutions

  1. Make the theme function always return a plain object, e.g. theme={() => ({ ...myTheme })}
  2. Guard inside the function: return loadedTheme ?? {} instead of null/undefined
  3. If the theme is a static object, pass it directly (theme={myTheme}) rather than wrapping it in a function that may return non-objects
  4. Ensure the return value is not an array; spread arrays into an object or restructure the theme

Example fix

// before
<ThemeProvider theme={() => config?.theme ?? null}>
// after
<ThemeProvider theme={() => config?.theme ?? {}}>
Defensive patterns

Strategy: validation

Validate before calling

const resolved = typeof themeFn === 'function' ? themeFn(outerTheme) : themeFn
if (resolved == null || typeof resolved !== 'object' || Array.isArray(resolved)) {
  throw new TypeError('theme function must return a plain object')
}

Type guard

function isPlainTheme(t: unknown): t is Record<string, unknown> {
  return t != null && typeof t === 'object' && !Array.isArray(t)
}

Try / catch

try {
  render(<ThemeProvider theme={makeTheme}>{children}</ThemeProvider>)
} catch (e) {
  if (e.message.includes('[ThemeProvider]')) {
    console.error('theme function returned a non-object; falling back to {}')
    render(<ThemeProvider theme={{}}>{children}</ThemeProvider>)
  } else throw e
}

Prevention

When it happens

Trigger: Passing theme={fn} to <ThemeProvider> where fn returns null, undefined, a primitive (string/number), or an array; e.g. theme={() => null} or a factory that conditionally returns nothing. Only thrown when isDevelopment.

Common situations: Theme factory functions that early-return null when config isn't loaded yet; refactored theme objects accidentally turned into arrays; async data that hasn't resolved so the factory returns undefined.

Related errors


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