[Bug]: Usage host fingerprint uses os.hostname(), which is unstable in containers
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 23k
- Forks
- 5.9k
- Avg merge
- 11h 14m
- Merged PRs (30d)
- 357
Description
Area
apps/server
Steps to reproduce
- Run the T3 Code server in a Docker container, with
<T3 home>on a named volume so state persists (a normal remote-environment setup). - Use a provider for a while so usage records accumulate, and open Usage → Limits.
- Recreate the container —
docker compose up -d --force-recreate, or any image pull, which is what a nightly deploy does. - Open Usage → Limits again.
Expected behavior
The environment keeps one identity across container recreates. Usage stays attributed to a single host, and the list does not grow an entry per redeploy.
Actual behavior
Every recreate produces a new host identity, so the usage list accumulates one stale entry per deploy, each labelled with a dead 12-hex container ID.
UsageService fingerprints usage records by os.hostname():
// apps/server/src/usage/UsageService.ts:473
const hostId = NodeOS.hostname();
...
fingerprint: { hostId, provider, resolvedHomePath: dir, volumeId },
Inside a container, os.hostname() defaults to the container ID, which is regenerated on every recreate. Docker only keeps a hostname stable if hostname: is set explicitly in compose, and nothing in the container docs suggests it matters.
Observed on two hosts. The IDs shown in the UI a few deploys ago (34b08f9f0350, e12c9b64fb68) no longer exist anywhere; today the same two environments report:
primary 519d29be0f28
workstation b257a7fc38ac
Meanwhile each environment already has a stable identity that survives recreates, because it lives on the persisted volume:
/home/node/.t3/userdata/environment-id
1044d043-b1bd-4a13-8b32-03523cb35ca0 # primary
8a47e572-0500-451d-b58c-559fda9241c8 # workstation
So the durable identifier exists and is not the one used.
Two consequences beyond the clutter: usage history fragments across identities rather than accumulating per environment, and the labels are opaque — a container ID cannot be matched to a machine by looking at it, which is what led me here.
Impact
Minor bug or occasional failure
Version or commit
t3 v0.0.41-nightly.20260913.1658
Environment
Server in Docker (node:24.13.1-bookworm-slim), Debian 12, two remote Linux environments reached over a VPN. T3 home, provider credential directories, and the git worktree root are all named volumes; the container itself is disposable and recreated on every image update.
Workaround
Set hostname: explicitly in the compose service so the container keeps a stable name across recreates. That fixes the symptom but relies on every containerised deployment knowing to do it.
A fix in the server could prefer the persisted environment-id for the fingerprint's host component, fall back to os.hostname() when it is absent, or allow an explicit override (T3CODE_HOST_ID) for deployments where the hostname is not meaningful.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in apps/server/src/usage/UsageService.ts around line 473 and trace how the persisted environment-id is read and how usage fingerprints are formed. Check the existing usage and environment identity paths before choosing between the durable ID, hostname fallback, or an explicit override. Done means recreating a container with a persistent volume keeps one usage identity instead of adding a new host entry.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- docker, node.js, typescript
- Domain
- backend, devops
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 65/100