tailwindlabs/tailwindcss · error · Error

`source(…)` paths must be quoted.

Error message

`source(…)` paths must be quoted.

What it means

Thrown while parsing the parameters of a legacy `@tailwind utilities` directive when a `source(…)` argument is not wrapped in matching quotes. The parser explicitly allows `source(none)` unquoted, but every actual path must be a quoted string literal (`source('...')` or `source("...")`), otherwise the parser cannot safely distinguish it from a keyword.

Source

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

      let params = segment(node.params, ' ')
      for (let param of params) {
        if (param.startsWith('source(')) {
          let path = param.slice(7, -1)

          // Keyword: `source(none)`
          if (path === 'none') {
            root = path
            continue
          }

          // Explicit path: `source('…')`
          if (
            (path[0] === '"' && path[path.length - 1] !== '"') ||
            (path[0] === "'" && path[path.length - 1] !== "'") ||
            (path[0] !== "'" && path[0] !== '"')
          ) {
            throw new Error('`source(…)` paths must be quoted.')
          }

          root = {
            base: (ctx.context.sourceBase as string) ?? (ctx.context.base as string),
            pattern: path.slice(1, -1),
          }
        }
      }

      utilitiesNode = node
      features |= Features.Utilities
    }

    // Collect custom `@utility` at-rules
    if (node.name === '@utility') {
      if (ctx.parent !== null) {
        throw new Error('`@utility` cannot be nested.')
      }

View on GitHub (pinned to 16e94cbf7f)

Solutions

  1. Wrap the path in matching single or double quotes: `@tailwind utilities source('./src/**/*.html')`.
  2. Use `source(none)` (unquoted, the only permitted bareword) if you want to disable automatic source detection.
  3. Remove the legacy `@tailwind utilities` directive entirely and use `@source` at-rules (the v4 idiom) for explicit candidate scanning.

Example fix

/* before */
@tailwind utilities source(./src/**/*.html);

/* after */
@tailwind utilities source('./src/**/*.html');
Defensive patterns

Strategy: validation

Validate before calling

// Validate every source(...) argument in a @tailwind utilities directive.
const SOURCE_ARG = /source\(([^)]*)\)/g

function validateUtilitiesSource(directive: string): string[] {
  const errors: string[] = []
  for (const m of directive.matchAll(SOURCE_ARG)) {
    const inner = m[1].trim()
    if (inner === 'none') continue
    if (!(inner.startsWith('"') && inner.endsWith('"')) &&
        !(inner.startsWith("'") && inner.endsWith("'"))) {
      errors.push(`source(${inner}) must be quoted`)
    }
  }
  return errors
}

Prevention

When it happens

Trigger: Writing `@tailwind utilities source(./src/**/*.html)` (unquoted), or using mismatched quotes like `source("./src')`. Fires per `source(…)` segment inside the directive params.

Common situations: Upgrading a v3 stylesheet that used `@tailwind utilities` with `source(...)` and dropping the quotes during the edit. Copy-pasting glob examples from docs that stripped quotes in formatting.

Related errors


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