tailwindlabs/tailwindcss · error · Error
Unsupported content value: ${pattern}
Error message
Unsupported content value: ${pattern} What it means
The upgrade codemod that migrates a v3 JS config reads the legacy `content` field and maps each entry to a `{ base, pattern }` source glob. Every pattern must be a string; if a `content.files` entry is an object, number, or array element, the codemod cannot turn it into a glob and throws. This guards against malformed v3 configs that happened to be tolerated by v3's looser runtime.
Source
Thrown at packages/@tailwindcss-upgrade/src/codemods/config/migrate-js-config.ts:368
if (!unresolvedConfig.content) return false
if (Array.isArray(unresolvedConfig.content)) return false
if (unresolvedConfig.content.relative) return true
if (unresolvedConfig.future === 'all') return false
return unresolvedConfig.future?.relativeContentPathsByDefault ?? false
})()
let sourceGlobs = Array.isArray(unresolvedConfig.content)
? unresolvedConfig.content.map((pattern) => ({ base, pattern }))
: (unresolvedConfig.content?.files ?? []).map((pattern) => {
if (typeof pattern === 'string' && contentIsRelative) {
return { base: path.dirname(configPath), pattern: pattern }
}
return { base, pattern }
})
for (let { base, pattern } of sourceGlobs) {
if (typeof pattern !== 'string') {
throw new Error('Unsupported content value: ' + pattern)
}
let sourceFiles = patternSourceFiles({
base,
pattern: pattern[0] === '!' ? pattern.slice(1) : pattern,
negated: pattern[0] === '!',
})
let autoContentContainsAllSourceFiles = true
for (let sourceFile of sourceFiles) {
if (!autoContentFiles.includes(sourceFile)) {
autoContentContainsAllSourceFiles = false
break
}
}
if (!autoContentContainsAllSourceFiles) {
sources.push({ base, pattern })View on GitHub (pinned to 16e94cbf7f)
Solutions
- Edit the v3 config so every `content` / `content.files` entry is a plain string glob before running the upgrade.
- Replace `raw` object entries with an actual file the glob can point at.
- Re-run `npx @tailwindcss/upgrade` after fixing the config.
Example fix
// before (v3 config)
module.exports = { content: { files: [{ raw: '<div class="p-4">' }] } }
// after
module.exports = { content: ['./src/**/*.html'] } Defensive patterns
Strategy: validation
Validate before calling
function assertContentStrings(content: unknown): string[] {
const files = Array.isArray(content) ? content : (content as any)?.files ?? []
for (const f of files) {
if (typeof f !== 'string') {
throw new Error(`Unsupported content entry (must be string): ${JSON.stringify(f)}`)
}
}
return files as string[]
} Type guard
function isStringContentArray(v: unknown): v is string[] {
return Array.isArray(v) && v.every(x => typeof x === 'string')
} Prevention
- Keep content/content.files entries as plain string globs.
- Avoid the legacy { raw: '...' } object form; extract to a real file.
- Sanitize programmatically-built content arrays before upgrade.
When it happens
Trigger: A `tailwind.config.js` whose `content` is `{ files: [ { raw: '…' }, './src/**' ] }` (object entries), or `content: ['./x', 42]`. The `typeof pattern !== 'string'` guard at migrate-js-config.ts:368 throws and concatenates the non-string value.
Common situations: Legacy configs using the undocumented `content.files[].raw` object form, or configs programmatically pushing non-string values into `content`.
Related errors
- Could not find the Tailwind CSS v3 `prefix` configuration in
- You have one or more stylesheets that are imported into a ut
- Cannot find any CSS files that reference Tailwind CSS. Befor
- No configuration file found for ${highlight(relative(start))
- Tailwind CSS is not installed
AI-assisted analysis of tailwindlabs/tailwindcss@16e94cbf7f (2026-08-12).
Data as JSON: /api/errors/172e82ccdcf70445.
Report an issue: GitHub.