-
Notifications
You must be signed in to change notification settings - Fork 11
Guides Unity Devcontainer Licensing
Unity will not compile without an activated license, and every container rebuild looks like a brand
new machine to Unity's licensing service. This guide gets scripts/unity/compile.sh and
scripts/unity/run-tests.sh running in a Codespace or a local dev container, and tells you which
error message means what.
Start by asking the repo what is missing -- this runs no Docker and takes a second:
npm run unity:validate===============================================================
Unity License Setup Validation
===============================================================
1. Checking credentials...
[FAIL] No credentials found (set env vars or run: npm run unity:setup-license)
2. Checking license files...
[INFO] .unity-secrets/license.ulf not present (online activation path only)
3. Checking license cache directory...
[PASS] Cache directory exists: /home/vscode/.unity-test-project/.unity-license-cache
[PASS] Cache directory is writable
[INFO] No cached license artifacts found (first run will activate)
4. Checking Docker setup...
[PASS] Docker command is available
[PASS] Docker daemon is running
5. Checking required scripts...
[PASS] scripts/unity/run-unity-docker.sh exists
[PASS] scripts/unity/compile.sh exists
[PASS] .devcontainer/post-create.sh exists
Fix whatever it reports, then run npm run unity:compile.
scripts/unity/run-unity-docker.sh supports three, and picks between them from which variables are
set:
| License | Set these | Notes |
|---|---|---|
| Personal (recommended) |
UNITY_EMAIL, UNITY_PASSWORD
|
Online activation. Personal cannot use .alf / .ulf at all. |
| Pro / Plus |
UNITY_SERIAL, UNITY_EMAIL, UNITY_PASSWORD
|
All three are required; an incomplete set fails early. |
Manual .ulf
|
UNITY_LICENSE (or .unity-secrets/license.ulf) |
Serial-based licenses only, and machine-specific -- see below. |
Two optional variables tune the timeouts (seconds): UNITY_LICENSE_ACTIVATION_TIMEOUT (default
300) and UNITY_LICENSE_RETURN_TIMEOUT (default 300).
Either export the variables in the shell you run the scripts from:
export UNITY_EMAIL="you@example.com"
export UNITY_PASSWORD="..."Or write them once to a file the scripts load automatically:
npm run unity:setup-licenseThat writes .unity-secrets/credentials.env, which is gitignored.
run-unity-docker.sh loads it whenever the environment variables are not already set, and also picks
up .unity-secrets/license.ulf into UNITY_LICENSE if that file exists.
- Open the repository on GitHub.
- Go to
Settings->Secrets and variables. - Choose
Codespaces(Codespaces-only) orActions(repository-level, reused by workflows). - Add
UNITY_EMAILandUNITY_PASSWORDwithNew repository secret.
Codespaces injects them as environment variables inside the devcontainer; run-unity-docker.sh
forwards them into the Unity container with Docker -e flags. See
Managing encrypted secrets for your codespaces.
It mounts a host cache into the Unity container, so an activation survives container restarts:
${UNITY_TEST_PROJECT_DIR}/.unity-license-cache/local-share-unity3d -> /root/.local/share/unity3d
${UNITY_TEST_PROJECT_DIR}/.unity-license-cache/config-unity3d -> /root/.config/unity3d
UNITY_TEST_PROJECT_DIR defaults to /home/vscode/.unity-test-project, so the cache lives in
/home/vscode/.unity-test-project/.unity-license-cache. Override the cache location with
UNITY_LICENSE_CACHE_DIR.
The cache holds Unity license identity — Unity_lic.ulf, UnityEntitlementLicense.xml and the
entitlement audit log — so it must never sit under .artifacts, the tree CI uploads artifacts
from. When the test project is itself inside .artifacts (the .unitypackage export puts it
there), the cache moves to RUNNER_TEMP, or the system temp directory when that is unset, and a
UNITY_LICENSE_CACHE_DIR pointing into .artifacts is refused. The rule matches the one the
Windows runner already follows for its activation log, and one derivation in
scripts/unity/lib/license-cache-dir.sh answers it for every Docker entry point.
Before running any Unity command, it verifies that at least one of these exists, and fails early pointing back here if none do:
/root/.local/share/unity3d/Unity/Unity_lic.ulf
/root/.config/unity3d/Unity/Unity_lic.ulf
/root/.local/share/unity3d/Unity/UnityEntitlementLicense.xml
/root/.config/unity3d/Unity/UnityEntitlementLicense.xml
Online activation also writes its raw log to
/root/.config/unity3d/.activation-<timestamp>.log. That directory is the mounted cache, so the log
survives the run and can be attached to a Unity support ticket.
Activation failures are classified from the activation log, and online activation is never re-run: a
hard licensing rejection fails fast and deliberately skips the .ulf fallback, while a transient or
network failure -- and any unconfirmed outcome the script cannot classify -- falls back to the .ulf
in UNITY_LICENSE when one is set. A machine-registration problem tries that same .ulf once and
otherwise stops with an actionable message. With no .ulf available, each of those paths fails the
run.
After a Pro serial activation starts, the Docker wrapper attempts license return on every exit, including a partial activation that never produces a usable license file. The failed activation still fails the run. A successful return command is not sufficient cleanup evidence: CI retains its central confirmation gate and quarantines an unconfirmed return. See #724.
Found 0 entitlement groups and 0 free entitlements matching requested entitlement ids
Error: 'com.unity.editor.headless' was not found.
This is a licensing-service decision about your account, not a missing command-line flag. The repo
already runs Unity with the correct headless flags (-batchmode -nographics -quit), and there is no
"headless toggle" in the Unity dashboard to turn on. Switching the build target to Dedicated Server
does not help either: that target is for built player binaries, while these scripts run
unity-editor in headless mode, which still needs an editor license.
Usual causes are the wrong Unity account for the license, a Personal account attempting a Pro-only
path, or an expired entitlement. Verify the account can activate the license type you are asking for,
confirm UNITY_SERIAL / UNITY_EMAIL / UNITY_PASSWORD agree for Pro, re-run, and check that
artifacts appear in the cache. If it persists, open a Unity support ticket with the saved activation
log.
The container's machine identity is not registered with your Unity account -- typical on the first
run in a fresh container or Codespace. If UNITY_LICENSE is set, run-unity-docker.sh tries that
.ulf once, in case it was generated for this machine, and continues when it produces a license
artifact. If it does not -- or if no .ulf was supplied at all -- the run stops there, because Unity
Personal cannot recover through manual .alf upload.
- Personal: activate through Unity Hub on an interactive machine, or attach the saved activation log to a Unity support request.
-
Serial-based license: follow Manual activation and
place the result at
.unity-secrets/license.ulf.
Machine bindings don't match
.ulf files are encrypted with machine-specific hardware identifiers, so they cannot move between
computers, between Docker containers (each container is a new "machine"), or between Codespaces
instances. Rebuilding the devcontainer invalidates one too.
Use online activation instead (UNITY_EMAIL + UNITY_PASSWORD). It issues a machine-specific
license inside the container, caches the artifact, reuses it on later runs without re-authenticating,
survives image rebuilds, and behaves the same in Codespaces, CI and local containers.
The first activation probably failed silently -- look for the entitlement errors above. Then:
ls -la ~/.unity-test-project/.unity-license-cache/
rm -rf ~/.unity-test-project/.unity-license-cache/
npm run unity:compileIf npm run unity:validate passes but compilation still fails, run Unity directly and read the full
log:
bash scripts/unity/run-unity-docker.sh -batchmode -nographics -quit -projectPath /project -logFile -Unity Personal cannot use this path. For a paid license with a serial key:
-
Generate the activation file:
npm run unity:generate-activation
This runs
scripts/unity/generate-activation.sh, which requiresUNITY_SERIAL, spins up a Docker container, calls-createManualActivationFile, and copies the result to.unity-secrets/manual-activation.alf. A plain compile run does not produce one. -
Upload the
.alfat https://license.unity3d.com/manual and log in with your Unity account. -
Enter your serial, download the
.ulf, and save it as.unity-secrets/license.ulf. -
Retry:
npm run unity:retry-license
scripts/unity/retry-license.shchecks that.unity-secrets/license.ulfis present, clears stale cached license artifacts so Unity re-reads the new file, and re-runscompile.sh.
The .ulf you get back only works on the machine that produced the .alf.
| Item | Persists? | Why |
|---|---|---|
.unity-secrets/credentials.env |
Yes | Gitignored workspace file, survives all rebuilds |
.unity-license-cache/ directory |
Yes | Docker persistent volume |
License artifacts (.ulf / .xml) |
Yes | Stored inside that persistent cache |
/root/.local/share/unity3d inside container |
No | Recreated from the persistent volume on each run |
| Docker image layers | No | Rebuilt each time, though cached locally |
So after one successful activation, later compiles reuse the cached license and do not
re-authenticate. .devcontainer/post-create.sh sets the cache directory permissions when the
container is created, and .devcontainer/post-start.sh re-asserts ownership of
~/.unity-test-project on every start if Docker has reset it. Unity still contacts the network to
confirm the license is active.
- Run
npm run unity:validatefirst. - Confirm the credentials are visible to the shell running the script, or present in
.unity-secrets/credentials.env(and.unity-secrets/license.ulffor the manual path). - Confirm
~/.unity-test-project/.unity-license-cache/exists and is writable. - Match any Unity error against Troubleshooting by error message before retrying -- entitlement and machine-registration failures do not resolve on a retry.
- Capture the activation log from
/root/.config/unity3d/before opening a support ticket.
📦 Unity Helpers | 📖 Documentation | 🐛 Issues | 📜 MIT License
- Inspector Button
- Inspector Conditional Display
- Inspector Grouping Attributes
- Inspector Inline Editor
- Inspector Overview
- Inspector Selection Attributes
- Inspector Settings
- Inspector Validation Attributes
- Utility Components
- Visual Components
- Data Structures
- Helper Utilities
- Math And Extensions
- Pooling Guide
- Random Generators
- Reflection Helpers
- Singletons
- Asset Change Detection
- Asset Validation
- Authored Asset Validation
- Editor Tools Guide
- Failed Tests Exporter
- Sprite Animation Motion
- Test Run Reporter
- Unity Method Analyzer
- Ai Model Backends
- Bundled Assembly Conflicts
- Mcp Ecosystem
- Mcp Local Setup
- Odin Migration Guide
- Unity Devcontainer Licensing