Skip to content

All @tailwindcss/cli commands handing forever docker builds #17781

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
ghmeier opened this issue Apr 24, 2025 · 9 comments
Closed

All @tailwindcss/cli commands handing forever docker builds #17781

ghmeier opened this issue Apr 24, 2025 · 9 comments

Comments

@ghmeier
Copy link

ghmeier commented Apr 24, 2025

What version of Tailwind CSS are you using?

v^4.1.0

What build tool (or framework if it abstracts the build tool) are you using?

Docker

What version of Node.js are you using?

v22.15.0

What browser are you using?

N/A

What operating system are you using?

darwin/arm64 and linux/arm64

Reproduction URL

https://github.com/ghmeier/tailwind-repro

The docker build hangs indefinitely when running:

docker build . 

Describe your issue

When running any tailwind while building docker containers for any architecture (the issue is reproducible when running docker buildx build --platform linux/amd64) any command that utilizes tailwind cli hangs. The repro case provided above is a minimal example where just running npx @tailwindcss/cli -v hangs indefinitely, but this also happens when building css using the cli directly or via webpack. Running the same command on my M1 Macbook pro resolves correctly.

Including DEBUG=1 does not resolve the issue, the command doesn't output anything.

The repro cases uses node:22.15.0-alpine3.20 but I've yet to find a base image that solves the issue.

I've looked through the couple of other issues and this looks most similar to #15730, but not quite the same.

@ghmeier
Copy link
Author

ghmeier commented Apr 24, 2025

Ok, I'm working to narrow down the version this was introduced in and when I use 4.0.17 (npm i @tailwindcss/[email protected] [email protected]), the fails with the following error:

 => ERROR [4/4] RUN npx @tailwindcss/cli -v                                                                                                                                                                      1.8s
------                                                                                                                                                                                                                
 > [4/4] RUN npx @tailwindcss/cli -v:                                                                                                                                                                                 
#8 1.199                                                                                                                                                                                                              
#8 1.199 thread '<unnamed>' panicked at crates/oxide/src/scanner/allowed_paths.rs:115:10:                                                                                                                             
#8 1.199 called `Option::unwrap()` on a `None` value                                                                                                                                                                  
#8 1.199 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
#8 1.208 fatal runtime error: failed to initiate panic, error 2532534672
#8 1.757 npm error path /
#8 1.758 npm error command failed
#8 1.758 npm error signal SIGABRT
#8 1.758 npm error command sh -c tailwindcss -v
#8 1.760 npm error A complete log of this run can be found in: /root/.npm/_logs/2025-04-24T19_56_00_902Z-debug-0.log
------
executor failed running [/bin/sh -c npx @tailwindcss/cli -v]: exit code: 1

Then using 4.1.0, it hangs forever.

@skeggse
Copy link

skeggse commented Apr 25, 2025

Got a little curious, tried to repro:

$ podman run -it --entrypoint npx node:22.15.0-alpine3.20 -y @tailwindcss/[email protected]
≈ tailwindcss v4.0.17

Usage:
  tailwindcss [--input input.css] [--output output.css] [--watch] [options…]

Options:
  -i, --input ··········· Input file
  -o, --output ·········· Output file [default: `-`]
  -w, --watch ··········· Watch for changes and rebuild as needed
  -m, --minify ·········· Optimize and minify the output
      --optimize ········ Optimize the output without minifying
      --cwd ············· The current working directory [default: `.`]
  -h, --help ············ Display usage information
npm notice
npm notice New major version of npm available! 10.9.2 -> 11.3.0
npm notice Changelog: https://github.com/npm/cli/releases/tag/v11.3.0
npm notice To update run: npm install -g [email protected]
npm notice



$ podman run -it --entrypoint npx node:22.15.0-alpine3.20 -y @tailwindcss/[email protected]
≈ tailwindcss v4.1.0

Usage:
  tailwindcss [--input input.css] [--output output.css] [--watch] [options…]

Options:
  -i, --input ··········· Input file
  -o, --output ·········· Output file [default: `-`]
  -w, --watch ··········· Watch for changes and rebuild as needed
  -m, --minify ·········· Optimize and minify the output
      --optimize ········ Optimize the output without minifying
      --cwd ············· The current working directory [default: `.`]
  -h, --help ············ Display usage information
npm notice
npm notice New major version of npm available! 10.9.2 -> 11.3.0
npm notice Changelog: https://github.com/npm/cli/releases/tag/v11.3.0
npm notice To update run: npm install -g [email protected]
npm notice

I can't imagine this is actually docker-specific, but... seemingly doesn't repro under podman? Or maybe I'm not understanding the repro instructions.

Weirdly, if I try to do -v it gives a cryptic error:

$ podman run -it --entrypoint npx node:22.15.0-alpine3.20 -y @tailwindcss/[email protected] -v
Error: Can't resolve 'tailwindcss' in '/'

I can repro the build from the repro repo, though. I have a vague recollection that podman build also uses buildx. strace suggests that it gets stuck in an epoll_pwait loop:

epoll_pwait(13, [], 1024, 4753, NULL, 8) = 0
write(16, "\1\0\0\0\0\0\0\0", 8)        = 8
epoll_pwait(13, [{events=EPOLLIN, data={u32=16, u64=16}}], 1024, 0, NULL, 8) = 1
read(16, "\1\0\0\0\0\0\0\0", 1024)      = 8
epoll_pwait(13, [], 1024, 0, NULL, 8)   = 0
epoll_pwait(13, [], 1024, 8100, NULL, 8) = 0
write(16, "\1\0\0\0\0\0\0\0", 8)        = 8
epoll_pwait(13, [{events=EPOLLIN, data={u32=16, u64=16}}], 1024, 0, NULL, 8) = 1
read(16, "\1\0\0\0\0\0\0\0", 1024)      = 8
epoll_pwait(13, [], 1024, 0, NULL, 8)   = 0
epoll_pwait(13, [], 1024, 8099, NULL, 8) = 0
write(16, "\1\0\0\0\0\0\0\0", 8)        = 8
epoll_pwait(13, [{events=EPOLLIN, data={u32=16, u64=16}}], 1024, 0, NULL, 8) = 1
read(16, "\1\0\0\0\0\0\0\0", 1024)      = 8
epoll_pwait(13, [], 1024, 0, NULL, 8)   = 0
epoll_pwait(13, [], 1024, 8099, NULL, 8) = 0
write(16, "\1\0\0\0\0\0\0\0", 8)        = 8
epoll_pwait(13, [{events=EPOLLIN, data={u32=16, u64=16}}], 1024, 0, NULL, 8) = 1
read(16, "\1\0\0\0\0\0\0\0", 1024)      = 8
epoll_pwait(13, [], 1024, 0, NULL, 8)   = 0
epoll_pwait(13,

@ghmeier
Copy link
Author

ghmeier commented May 1, 2025

Update - I tried this using v4.1.15 and still encountering the same issues.

@logandavis
Copy link

@thecrypticace sorry for the ping -- I see that you're active in the issues here. Have you seen this issue? It's been up for a couple weeks.

My sense of this issue is that recent versions of tailwind have the CLI stall out with no error in extremely common build environments (darwin/arm64 and linux/arm64 on docker). If I am understanding the issue correctly, the impact would be that no one with what I think is a pretty standard CI pipeline can upgrade to these Tailwind versions and then deploy their code. Seems like it would be very bad for adoption.

@thecrypticace
Copy link
Contributor

I haven't been able to reproduce these issues of the CLI hanging using the same docker environments on macOS (via Orbstack) or Windows (via Docker Desktop).

I spent some time last week trying various configurations to reproduce things but haven't seen anything yet. I'm not sure what the big cause is right now. Obviously multiple people are seeing this but so far it's been completely unreproducible for me (or anyone else on the team).

@logandavis
Copy link

I have a 2021 Apple MacBook Pro with an Apple M1 Pro chip running macOS Sequoia (15.4.1). Docker is installed via Docker Desktop and docker --version gives Docker version 20.10.16, build aa7e414

For me, @ghmeier's repro repo triggers the issue immediately:

➜ git clone [email protected]:ghmeier/tailwind-repro.git
Cloning into 'tailwind-repro'...
remote: Enumerating objects: 15, done.
remote: Counting objects: 100% (15/15), done.
remote: Compressing objects: 100% (9/9), done.
remote: Total 15 (delta 4), reused 15 (delta 4), pack-reused 0 (from 0)
Receiving objects: 100% (15/15), 8.52 KiB | 4.26 MiB/s, done.
Resolving deltas: 100% (4/4), done.

➜ cd tailwind-repro 

➜ which docker
/usr/local/bin/docker

➜ docker --version
Docker version 20.10.16, build aa7e414

➜ docker build . 
[+] Building 98.1s (8/8) FINISHED                                                                                                                                                
 => [internal] load build definition from Dockerfile                                                                                                                        0.0s
 => => transferring dockerfile: 184B                                                                                                                                        0.0s
 => [internal] load .dockerignore                                                                                                                                           0.0s
 => => transferring context: 2B                                                                                                                                             0.0s
 => [internal] load metadata for docker.io/library/node:22.15.0-alpine3.20                                                                                                  4.4s
 => [internal] load build context                                                                                                                                           0.0s
 => => transferring context: 32.48kB                                                                                                                                        0.0s
 => [1/4] FROM docker.io/library/node:22.15.0-alpine3.20@sha256:686b8892b69879ef5bfd6047589666933508f9a5451c67320df3070ba0e9807b                                            3.6s
 => => resolve docker.io/library/node:22.15.0-alpine3.20@sha256:686b8892b69879ef5bfd6047589666933508f9a5451c67320df3070ba0e9807b                                            0.0s
 => => sha256:774effcc5f3116e69df970e0b9898ad4471d64994d30853eaf148dafd828111a 1.73kB / 1.73kB                                                                              0.0s
 => => sha256:b549082e27a8be949a8306ea8f76776e636a2dfffc5565f4f009e79d6095d5c7 6.23kB / 6.23kB                                                                              0.0s
 => => sha256:94e9d8af22013aabf0edcaf42950c88b0a1350c3a9ce076d61b98a535a673dd9 4.09MB / 4.09MB                                                                              1.0s
 => => sha256:51e79a60053913ed118d04d0d8bcccb0ced38a47fa994357598b836138989237 49.64MB / 49.64MB                                                                            2.1s
 => => sha256:2edbe101eaf434baf4e0ed65c01420582b256ed6a72ce4ddd05b8173772e53f1 1.39MB / 1.39MB                                                                              0.8s
 => => sha256:686b8892b69879ef5bfd6047589666933508f9a5451c67320df3070ba0e9807b 6.43kB / 6.43kB                                                                              0.0s
 => => sha256:b7403708829fdfae7c44b682e57f4e576599434f8254b6c05a08b0254d0a87c6 443B / 443B                                                                                  1.0s
 => => extracting sha256:94e9d8af22013aabf0edcaf42950c88b0a1350c3a9ce076d61b98a535a673dd9                                                                                   0.2s
 => => extracting sha256:51e79a60053913ed118d04d0d8bcccb0ced38a47fa994357598b836138989237                                                                                   1.2s
 => => extracting sha256:2edbe101eaf434baf4e0ed65c01420582b256ed6a72ce4ddd05b8173772e53f1                                                                                   0.1s
 => => extracting sha256:b7403708829fdfae7c44b682e57f4e576599434f8254b6c05a08b0254d0a87c6                                                                                   0.0s
 => [2/4] COPY package.json package-lock.json input.css /                                                                                                                   0.1s
 => [3/4] RUN npm ci                                                                                                                                                        1.3s
 => CANCELED [4/4] RUN npx @tailwindcss/cli -i input.css -o out.css                                                                                                        88.7s
context canceled

(I cancelled the run manually after 90 seconds).

@thecrypticace
Copy link
Contributor

Ah okay you know what I think the repro I was testing was a different one because that one definitely hangs (well kinda). The CLI, because of it being run from the root, ends up scanning inside /sys/class/mdio_bus/fixed-0/device/subsystem/devices/… and gets stuck in there traversing directories.

I suspect this has to do with recursive symlinks of some kind. I thought we handled those but maybe the files have weird path characteristics causing problems there. It appears that the mdio_bus directory tree contains a metric ton of them. (/sys/class/mdio_bus/… is a virtual fs on linux that maps network interface related stuff so scanning/traversing it is useless anyway).

But, generally, running the CLI from the root of a container seems like a pretty bad idea. A proper docker container setup is almost always going to have a folder or a mount containing the app / site / whatever. The CLI should be run from there otherwise automatic source detection will end up traversing way more than it should. It's like if you ran the CLI at / on macOS or at C:/ on Windows.

I'll see if I can look into the symlink traversal behavior but the immediate "fix" is: run the CLI from a CWD that contains the sources you actually need to scan (e.g. not /)

@ghmeier
Copy link
Author

ghmeier commented May 6, 2025

Ok, thanks for the update! It seems like using a subdirectory solved the issue.

It'd be nice if there was a warning or error vs. radio silence.

@ghmeier ghmeier closed this as completed May 6, 2025
@thecrypticace
Copy link
Contributor

Yeah in this case it basically ends up in an infinite loop. I'll have to look into whether or not the JS event loop is event active while this is happening. (If it is then we should be able to output stuff, if not then we'd have to output stuff on the native side where we actually scan files).

I know @RobinMalfait is working on improving the debugging of file scanning in #17906 which should (hopefully) help with things like this I think.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants