tailwindlabs/tailwindcss · error · Error

No `loadStylesheet` function provided to `compile`

Error message

No `loadStylesheet` function provided to `compile`

What it means

Thrown by the default `loadStylesheet` stub assigned in `parseCss` when `CompileOptions.loadStylesheet` is omitted. Tailwind only invokes this callback while resolving `@import` statements via `substituteAtImports`, so the error means CSS containing `@import "..."` was compiled without a way to read external files. The library refuses to silently drop the imported file.

Source

Thrown at packages/tailwindcss/src/index.ts:83

    base: string
    module: Plugin | Config
  }>
  loadStylesheet?: (
    id: string,
    base: string,
  ) => Promise<{
    path: string
    base: string
    content: string
  }>
}

function throwOnLoadModule(): never {
  throw new Error('No `loadModule` function provided to `compile`')
}

function throwOnLoadStylesheet(): never {
  throw new Error('No `loadStylesheet` function provided to `compile`')
}

function parseThemeOptions(params: string) {
  let options = ThemeOptions.NONE
  let prefix = null

  for (let option of segment(params, ' ')) {
    if (option === 'reference') {
      options |= ThemeOptions.REFERENCE
    } else if (option === 'inline') {
      options |= ThemeOptions.INLINE
    } else if (option === 'default') {
      options |= ThemeOptions.DEFAULT
    } else if (option === 'static') {
      options |= ThemeOptions.STATIC
    } else if (option.startsWith('prefix(') && option.endsWith(')')) {
      prefix = option.slice(7, -1)
    }

View on GitHub (pinned to 16e94cbf7f)

Solutions

  1. Provide a `loadStylesheet: async (id, base) => ({ path, base, content })` callback in `CompileOptions` that reads the file (e.g. `fs.readFile`) or fetches the URL and returns its contents.
  2. If you do not need `@import` resolution, remove the `@import` statements from the input CSS so the loader is never called.
  3. If integrating via the PostCSS plugin, use `@tailwindcss/postcss` instead of calling `compile` directly — it supplies a working loader.

Example fix

// before
await compile(css) // css contains @import "./theme.css"

// after
import { readFile } from 'node:fs/promises'
import path from 'node:path'
await compile(css, {
  base: process.cwd(),
  loadStylesheet: async (id, base) => {
    const resolved = path.resolve(base, id)
    return { path: resolved, base: path.dirname(resolved), content: await readFile(resolved, 'utf8') }
  },
})
Defensive patterns

Strategy: validation

Validate before calling

// Before calling compile, detect @import and require a loader.
import { compile } from 'tailwindcss'

function needsStylesheetLoader(css: string): boolean {
  // crude but effective: matches @import (with optional layer/theme qualifiers)
  return /@import\s+(["'][^"']+["']|url\()/.test(css)
}

async function safeCompile(css: string, opts: CompileOptions = {}) {
  if (needsStylesheetLoader(css) && !opts.loadStylesheet) {
    throw new Error('CSS contains @import but no loadStylesheet was provided')
  }
  return compile(css, opts)
}

Prevention

When it happens

Trigger: Calling `compile(...)` or `__unstable__loadDesignSystem(...)` with CSS that contains one or more `@import` rules, while omitting `loadStylesheet` from the options object.

Common situations: Embedding the standalone `compile` API (or Oxide-integration layer) in a custom build pipeline, CLI, or test harness and forgetting to wire a file/URL loader. Migrating from `@tailwindcss/postcss` (which injects its own loader) to direct programmatic use.

Related errors


AI-assisted analysis of tailwindlabs/tailwindcss@16e94cbf7f (2026-08-12). Data as JSON: /api/errors/73ed876f192088b2. Report an issue: GitHub.