What happened
When I launch T3 Code using the AppImage nothing happens, it doesn't open. If I run with a terminal it returns immediately with exit code 0 (what I ran was <appimage-dir>/t3code.AppImage --no-sandbox)
The desktop app had auto-updated to 0.0.41-nightly.20260908.1377 a few hours earlier. The user never saw an error — the app simply quit to install and never came back.
Diagnosis
The auto-update replaced the user's AppImage with a 0-byte file and left it that way. bash cannot execve an empty file, so it falls back to running it as a shell script; an empty script exits 0 immediately, which is exactly the reported symptom.
-rwxr-xr-x 1 <user> <user> 0 Sep 8 01:37 <appimage-dir>/t3code.AppImage
Timeline reconstructed from logs/desktop.trace.ndjson plus inode timestamps (all times local, -0400):
| Time |
Event |
| 01:14:36 |
app start, channel nightly (allowPrerelease=true, allowDowngrade=true) |
| 01:14:51 → 01:34:38 |
update available 0.0.41-nightly.20260908.1377 on every poll |
| 01:36:57.996 |
downloading update |
| 01:37:09.338 |
download progress 100% |
| 01:37:09.344 |
pending/update-info.json written (sha512 verified, download intact) |
| 01:37:09.346 |
update downloaded — last updater log line anywhere |
| 01:37:09.848 |
trace ends; app quits to install |
| 01:37:14.162 |
t3code.AppImage re-created (birth), mtime copied from the downloaded file (01:37:09.339), mode 0755, size 0 |
| 01:37:14.249 |
downloaded AppImage removed from ~/.cache/t3code-updater/pending/ (only update-info.json remains) |
| — |
no further run appears in the trace: the post-install relaunch never happened |
The download itself was fine — it reached 100%, passed electron-updater's sha512 check, and update-info.json was written. The file was destroyed during install.
apps/desktop/src/updates/DesktopUpdates.ts calls quitAndInstall({ isSilent: true, isForceRunAfter: true }) and apps/desktop/src/electron/ElectronUpdater.ts is a thin wrapper over stock electron-updater (6.8.3 per pnpm-lock.yaml), so the install is AppImageUpdater.doInstall:
unlinkSync(appImageFile); // working AppImage deleted FIRST
...
if (basename(installerPath) === existingBaseName || !/\d+\.\d+\.\d+/.test(existingBaseName)) {
destination = appImageFile; // no x.y.z in the name → overwrite in place
}
execFileSync("mv", ["-f", installerPath, destination]); // result never verified
Two things combine here:
- The user's file is named
t3code.AppImage. It contains no x.y.z, so doInstall takes the overwrite-in-place branch rather than writing a new versioned file beside it.
~/.cache/t3code-updater and the AppImage are on different filesystems (/ vs a second NVMe mounted at /mnt/storage), so mv degrades from an atomic rename(2) to copy-then-delete. The copy produced 0 bytes; the preserved mtime and 0755 mode show mv ran to completion and reported success.
I could not reproduce a bad mv — three full-size (186 MB) copies across the same source→destination pair came out byte-exact — so the reason that one copy came out empty is not established. Environment notes that may matter: / is at 99% (2.6 GB free), and there was no ENOSPC in any log and no I/O or filesystem error in the kernel journal around 01:37.
What turns a bad copy into a bricked install is the surrounding design, and that part is independent of the root cause:
- the working AppImage is unlinked before the replacement is in place, so there is nothing to fall back to;
- nothing verifies the installed file's size or sha512 against the artifact that was just downloaded and verified;
- the app has already quit, so no failure can be surfaced to the user;
- the install step produces no log line at all.
DesktopUpdates.ts logs update downloaded and then calls quitAndInstall with no logging around it, and electron-updater's own logger is not wired into the trace. On this machine desktop-main.log, which used to capture electron-updater's stdout, was last written 2026-05-11 — so the entire install step is invisible after the fact.
Suggested directions, roughly in order of value:
- stage the downloaded artifact on the same filesystem as
$APPIMAGE (e.g. a dot-prefixed temp file in dirname($APPIMAGE)) so the swap is an atomic rename(2) and a partial copy is impossible;
- verify the installed file (size + sha512 against
update-info.json) before relaunching, and restore/abort if it does not match;
- keep the old AppImage until the new one is verified, instead of
unlinkSync first;
- log the install step and wire
autoUpdater.logger into the trace so the next occurrence leaves evidence.
Steps to reproduce
The bricking is deterministic given a failed copy; the failing copy itself was not reproducible on demand. Reproducing the fragile path:
- On Linux, put the AppImage on a filesystem different from the one holding
~/.cache/t3code-updater, and give it a filename with no x.y.z version in it (e.g. t3code.AppImage).
- Launch it and let the nightly channel find an update.
- Click install.
electron-updater unlinks the AppImage and mvs the downloaded file across the filesystem boundary onto that exact path.
- If that copy is short or empty for any reason, the app quits, never relaunches, and the AppImage is left unusable with no error and no log entry after
update downloaded.
To confirm the symptom directly, without the updater: : > t3code.AppImage && ./t3code.AppImage --no-sandbox; echo $? → prints 0, no window, no output.
Version
0.0.40 (CLI); desktop app was on the nightly channel updating to 0.0.41-nightly.20260908.1377
Environment
Ubuntu 24.04.4 LTS, kernel 6.8.0-139-generic, x86_64, Node v24.15.0, electron 43.4.1, electron-updater 6.8.3, GNU coreutils 9.4 (mv). AppImage and updater cache on separate ext4 filesystems; root filesystem 99% full (2.6 GB free).
Evidence
# logs/desktop.trace.ndjson — updater events, last run before the app disappeared
01:14:36.466 INFO desktop-updater | using update channel | {"channel":"nightly","allowPrerelease":true,"allowDowngrade":true,"fullChangelog":true}
01:34:38.789 INFO desktop-updater | update available | {"version":"0.0.41-nightly.20260908.1377","releaseNoteGroups":6,"omittedReleaseCount":4}
01:36:57.996 INFO desktop-updater | downloading update | {"channel":"desktop:update-download"}
01:37:09.289 INFO desktop-updater | download progress | {"percent":99}
01:37:09.338 INFO desktop-updater | download progress | {"percent":100}
01:37:09.346 INFO desktop-updater | update downloaded | {"version":"0.0.41-nightly.20260908.1377"}
# ...trace ends 01:37:09.848. No install log line, no error, no subsequent run.
# the installed binary afterwards
$ stat <appimage-dir>/t3code.AppImage
Size: 0 Blocks: 0 IO Block: 4096 regular empty file
Access: (0755/-rwxr-xr-x)
Modify: 2026-09-08 01:37:09.339021853 -0400 <- copied from the downloaded artifact
Change: 2026-09-08 01:37:14.249055832 -0400
Birth: 2026-09-08 01:37:14.162055238 -0400 <- created by `mv` during doInstall
$ file <appimage-dir>/t3code.AppImage
<appimage-dir>/t3code.AppImage: empty
# the downloaded artifact was intact and is now gone (moved by doInstall)
$ ls -la ~/.cache/t3code-updater/pending/
-rw-rw-r-- 1 ... 198 Sep 8 01:37 update-info.json # dir mtime 01:37:14.249
$ cat ~/.cache/t3code-updater/pending/update-info.json
{"fileName":"T3-Code-0.0.41-nightly.20260908.1377-x86_64.AppImage","sha512":"Ip8hDFqjC+5pcl...","isAdminRightsRequired":false}
# release asset size for that build: 186,531,181 bytes
# separate filesystems for cache and target
/dev/nvme0n1p1 234G 220G 2.6G 99% / <- ~/.cache/t3code-updater
/dev/nvme1n1p5 871G 611G 217G 74% /mnt/... <- the AppImage
Related issues
#9945 / #9946 (closed, not merged) and #8944 / #8983 all concern AppImage filenames across updates, but they are about dock pins and desktop entries breaking, not about the update destroying the binary. No open or closed issue covers an update leaving a 0-byte AppImage. Nothing on main since v0.0.40 touches the install path, so this is not fixed in a newer release.
Fix applied or workaround
Re-downloaded T3-Code-0.0.41-nightly.20260908.1387-x86_64.AppImage onto the same filesystem as the target, verified its sha512 against nightly-linux.yml, then mv'd it into place and chmod 755. Confirmed working: the app booted, backend ready and main window created appear in the trace, and the updater reports no updates available. A verified backup copy was left beside it, since the next auto-update can hit the same path.
Filed by
claude (Opus 5, 1M context) via t3 triage
What happened
The desktop app had auto-updated to
0.0.41-nightly.20260908.1377a few hours earlier. The user never saw an error — the app simply quit to install and never came back.Diagnosis
The auto-update replaced the user's AppImage with a 0-byte file and left it that way.
bashcannotexecvean empty file, so it falls back to running it as a shell script; an empty script exits 0 immediately, which is exactly the reported symptom.Timeline reconstructed from
logs/desktop.trace.ndjsonplus inode timestamps (all times local,-0400):nightly(allowPrerelease=true,allowDowngrade=true)update available 0.0.41-nightly.20260908.1377on every polldownloading updatedownload progress 100%pending/update-info.jsonwritten (sha512 verified, download intact)update downloaded— last updater log line anywheret3code.AppImagere-created (birth), mtime copied from the downloaded file (01:37:09.339), mode 0755, size 0~/.cache/t3code-updater/pending/(onlyupdate-info.jsonremains)The download itself was fine — it reached 100%, passed electron-updater's sha512 check, and
update-info.jsonwas written. The file was destroyed during install.apps/desktop/src/updates/DesktopUpdates.tscallsquitAndInstall({ isSilent: true, isForceRunAfter: true })andapps/desktop/src/electron/ElectronUpdater.tsis a thin wrapper over stockelectron-updater(6.8.3perpnpm-lock.yaml), so the install isAppImageUpdater.doInstall:Two things combine here:
t3code.AppImage. It contains nox.y.z, sodoInstalltakes the overwrite-in-place branch rather than writing a new versioned file beside it.~/.cache/t3code-updaterand the AppImage are on different filesystems (/vs a second NVMe mounted at/mnt/storage), somvdegrades from an atomicrename(2)to copy-then-delete. The copy produced 0 bytes; the preserved mtime and 0755 mode showmvran to completion and reported success.I could not reproduce a bad
mv— three full-size (186 MB) copies across the same source→destination pair came out byte-exact — so the reason that one copy came out empty is not established. Environment notes that may matter:/is at 99% (2.6 GB free), and there was noENOSPCin any log and no I/O or filesystem error in the kernel journal around 01:37.What turns a bad copy into a bricked install is the surrounding design, and that part is independent of the root cause:
DesktopUpdates.tslogsupdate downloadedand then callsquitAndInstallwith no logging around it, andelectron-updater's own logger is not wired into the trace. On this machinedesktop-main.log, which used to capture electron-updater's stdout, was last written 2026-05-11 — so the entire install step is invisible after the fact.Suggested directions, roughly in order of value:
$APPIMAGE(e.g. a dot-prefixed temp file indirname($APPIMAGE)) so the swap is an atomicrename(2)and a partial copy is impossible;update-info.json) before relaunching, and restore/abort if it does not match;unlinkSyncfirst;autoUpdater.loggerinto the trace so the next occurrence leaves evidence.Steps to reproduce
The bricking is deterministic given a failed copy; the failing copy itself was not reproducible on demand. Reproducing the fragile path:
~/.cache/t3code-updater, and give it a filename with nox.y.zversion in it (e.g.t3code.AppImage).electron-updaterunlinks the AppImage andmvs the downloaded file across the filesystem boundary onto that exact path.update downloaded.To confirm the symptom directly, without the updater:
: > t3code.AppImage && ./t3code.AppImage --no-sandbox; echo $?→ prints0, no window, no output.Version
0.0.40 (CLI); desktop app was on the
nightlychannel updating to 0.0.41-nightly.20260908.1377Environment
Ubuntu 24.04.4 LTS, kernel 6.8.0-139-generic, x86_64, Node v24.15.0, electron 43.4.1, electron-updater 6.8.3, GNU coreutils 9.4 (
mv). AppImage and updater cache on separate ext4 filesystems; root filesystem 99% full (2.6 GB free).Evidence
Related issues
#9945 / #9946 (closed, not merged) and #8944 / #8983 all concern AppImage filenames across updates, but they are about dock pins and desktop entries breaking, not about the update destroying the binary. No open or closed issue covers an update leaving a 0-byte AppImage. Nothing on
mainsince v0.0.40 touches the install path, so this is not fixed in a newer release.Fix applied or workaround
Re-downloaded
T3-Code-0.0.41-nightly.20260908.1387-x86_64.AppImageonto the same filesystem as the target, verified its sha512 againstnightly-linux.yml, thenmv'd it into place andchmod 755. Confirmed working: the app booted,backend readyandmain window createdappear in the trace, and the updater reportsno updates available. A verified backup copy was left beside it, since the next auto-update can hit the same path.Filed by
claude (Opus 5, 1M context) via
t3 triage