If your Windows user folder looks like C:\Users\dana.o'neil or C:\Users\JeanD'Arc, Expo Android builds can fail in places that seem to have nothing to do with each other. We hit two of them on the same machine:

  • AAPT2 doesn't start. The release build stopped in mergeReleaseResources because the AAPT2 daemon failed to start. The Gradle home was under the user profile, in a long path that contained the apostrophe.
  • Gradle workers can't find their main class. Our earlier build script had to move the Gradle home out of the profile because Gradle's worker processes failed with Java unable to find GradleWorkerMain.

We didn't keep the raw logs, so the messages below are reconstructed from the task names and the Gradle and AGP error formats:

> Task :app:mergeReleaseResources FAILED
AAPT2 aapt2-<version>-windows Daemon #0: Daemon startup failed
Error: Could not find or load main class worker.org.gradle.process.internal.worker.GradleWorkerMain

Other developers report the same Gradle worker error with non-ASCII user names. Below is the part of the story we could verify in source code, and the workaround.

Why an apostrophe matters

Windows has a limit on command-line length, so Gradle often launches Java processes with an argument file: it writes the arguments (including a long classpath) into a file and starts java @that-file.

Two details then collide:

  1. The JDK treats ' as a quote character in argument files. The launcher's parser handles a single quote exactly like a double quote. It opens a quoted section that runs until the next matching quote or the end of the line. The java documentation only talks about double quotes, so this is easy to miss.
  2. Gradle doesn't protect the apostrophe. When it writes an argument file, Gradle 9.3.1 wraps an argument in double quotes only if it contains whitespace or #, and escapes only \ and ".

So a classpath entry like C:\Users\dana.o'neil\.gradle\caches\…\some.jar goes into the file unquoted. The JDK reads ' as the start of a quoted section, and from that point on the classpath is mangled. The worker JVM then can't find its own main class.

Two consequences follow:

  • It depends on the exact path. Reading the code (we haven't tested it), if the same folder name also contains a space (C:\Users\Dana O'Neil), Gradle wraps it in double quotes, and inside double quotes the apostrophe is harmless. That's why one machine fails and a colleague's doesn't.
  • Not every tool breaks. On our machine, a JDK that Gradle downloaded into %USERPROFILE%\.gradle\jdks, with the apostrophe in the path, unpacked and worked fine.

What we haven't proven: the exact mechanism behind the AAPT2 failure. AAPT2 is a native executable, and AGP takes it from the Gradle cache, which by default lives under your user folder. Our failing attempt combined the apostrophe with a long path (139 characters for the workspace alone), and moving to a short path without the apostrophe fixed it. We didn't test the two causes separately.

The workaround

You can't easily rename a Windows user folder, so keep the build tools out of it.

1. Move the Gradle home

This is the step that fixed both failures for us:

mkdir C:\gh
$env:GRADLE_USER_HOME = "C:\gh"

To make it permanent, set GRADLE_USER_HOME as a user environment variable (System Properties → Environment Variables). User-level gradle.properties now lives in C:\gh too: copy over any settings you had in %USERPROFILE%\.gradle\gradle.properties. The first build downloads its dependencies again.

2. Build the project outside your profile

Clone or copy the project to a short folder such as C:\b\app. This avoids the apostrophe in the project's own paths and the 260-character limit at the same time (see our article on ninja's "Filename longer than 260 characters").

3. If it still fails: move the temp folder

Our earlier script also pointed TEMP and TMP to a short folder for the build session:

mkdir C:\gt
$env:TEMP = "C:\gt"; $env:TMP = "C:\gt"

We haven't isolated whether this step is needed on its own. Treat it as an extra measure.

4. Stop old daemons

cd C:\b\app\android
.\gradlew.bat --stop
.\gradlew.bat app:bundleRelease

How WinBuild handles it

WinBuild never builds inside your user profile, wherever your project lives:

  • The workspace where the project is copied and built may only contain letters, digits, ., - and _, with at most 40 characters: no apostrophes, no spaces. The check runs before any process starts.
  • The Gradle home of each attempt sits under a short root you choose (--gradle-root, same character rules), not under %USERPROFILE%\.gradle.
  • TEMP, TMP and Java's java.io.tmpdir point to a tmp folder inside that Gradle home for the Gradle process, so step 3 is built in too.
  • If AAPT2 still fails to start, the report says AAPT2_DAEMON instead of leaving you to read the Gradle log. That category correctly identified the failure described above.
winbuild bundle --workspace C:\wb\app1 --gradle-root C:\wb --allow-config-code

Your project can stay in C:\Users\dana.o'neil\…, and WinBuild only reads it.

Sources

External sources consulted on 20 October 2026. Figures about WinBuild come from our own build records.

Private alpha

Building Expo Android releases on Windows?

WinBuild is in private alpha. Testers get the package directly and help validate different machines and Expo projects.

Request alpha access →No checkout yet · direct founder feedback

← All articles