Disclosure: This issue (text, minimal repro, and analysis) was generated by AI — Claude Opus 4.7 — and reviewed by me before posting.
What version of Tailwind CSS are you using?
v4.3.0
What build tool (or framework if it abstracts the build tool) are you using?
CLI only (tailwindcss canonicalize)
What version of Node.js are you using?
v25.8.1
What operating system are you using?
macOS 14 / Darwin 24.6.0 (arm64)
Describe your issue
tailwindcss canonicalize crashes with TypeError: The "path" argument must be of type string or an instance of Buffer or URL. Received undefined whenever the loaded CSS registers a plugin that uses matchComponents with a values map, and the input class list contains an arbitrary-value utility (e.g. border-[1.5px], text-[26px]).
The crash comes from the user plugin's matcher callback being invoked with a value that is not in the values map, so destructured properties are undefined and any fs.readFileSync(fullPath) in the callback throws.
This affects the default Phoenix Heroicons plugin shipped by phx.new (https://github.com/phoenixframework/phoenix/blob/main/installer/templates/phx_assets/heroicons.js), so canonicalize is unusable for the entire Phoenix LiveView ecosystem out of the box.
Minimal reproduction
plugin-min.js:
const plugin = require("tailwindcss/plugin")
const fs = require("fs")
module.exports = plugin(function({matchComponents}) {
matchComponents({
"myicon": ({fullPath}) => {
let content = fs.readFileSync(fullPath).toString()
return { content: `'${content}'` }
}
}, { values: { foo: { fullPath: "/etc/hosts" } } })
})
app.css:
@import "tailwindcss" source(none);
@plugin "./plugin-min.js";
$ npx @tailwindcss/cli canonicalize --css ./app.css "border-[1.5px] flex"
The "path" argument must be of type string or an instance of Buffer or URL. Received undefined
Triggers and non-triggers
With this CSS loaded:
| Input |
Result |
flex |
OK |
flex p-4 |
OK |
myicon-foo |
OK (real value, matcher gets {fullPath: "/etc/hosts"}) |
border-[1.5px] flex |
crash |
text-[26px] md:text-4xl |
crash |
text-base leading-[1.1] |
crash |
border-[1.5px] alone |
OK |
text-[26px] alone |
OK |
So the trigger is "arbitrary utility + at least one other utility", which suggests canonicalize is exploring shorthand collapse possibilities and invoking the matcher with a candidate that doesn't exist in values.
Expected behaviour
canonicalize should not invoke user matchComponents callbacks with values that are absent from the values map. Alternatively, if it must probe matchers speculatively, it should swallow exceptions from those calls — they're being used for analysis, not output generation.
What version of Tailwind CSS are you using?
v4.3.0
What build tool (or framework if it abstracts the build tool) are you using?
CLI only (
tailwindcss canonicalize)What version of Node.js are you using?
v25.8.1
What operating system are you using?
macOS 14 / Darwin 24.6.0 (arm64)
Describe your issue
tailwindcss canonicalizecrashes withTypeError: The "path" argument must be of type string or an instance of Buffer or URL. Received undefinedwhenever the loaded CSS registers a plugin that usesmatchComponentswith avaluesmap, and the input class list contains an arbitrary-value utility (e.g.border-[1.5px],text-[26px]).The crash comes from the user plugin's matcher callback being invoked with a value that is not in the
valuesmap, so destructured properties areundefinedand anyfs.readFileSync(fullPath)in the callback throws.This affects the default Phoenix Heroicons plugin shipped by
phx.new(https://github.com/phoenixframework/phoenix/blob/main/installer/templates/phx_assets/heroicons.js), so canonicalize is unusable for the entire Phoenix LiveView ecosystem out of the box.Minimal reproduction
plugin-min.js:app.css:Triggers and non-triggers
With this CSS loaded:
flexflex p-4myicon-foo{fullPath: "/etc/hosts"})border-[1.5px] flextext-[26px] md:text-4xltext-base leading-[1.1]border-[1.5px]alonetext-[26px]aloneSo the trigger is "arbitrary utility + at least one other utility", which suggests canonicalize is exploring shorthand collapse possibilities and invoking the matcher with a candidate that doesn't exist in
values.Expected behaviour
canonicalizeshould not invoke usermatchComponentscallbacks with values that are absent from thevaluesmap. Alternatively, if it must probe matchers speculatively, it should swallow exceptions from those calls — they're being used for analysis, not output generation.