Skip to content

[Bug]: Delegated worktree setup fails with ENAMETOOLONG on eCryptfs #21637

Open

Description

@seankoji

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/server

What happened

A T3-owned delegated task using isolation: "worktree" fails before its project setup command starts. The UI reports:

Workspace preparation failed during run setup script:
Project setup script operation 'openTerminal' failed for thread '<delegated-thread-id>' in '<worktree>'.

The setup output box is empty because terminal history lookup fails before the shell is opened.

Diagnosis

The terminal manager base64url-encodes the complete thread and terminal IDs into one filename. A delegated thread ID in this case is 129 bytes. With terminal ID setup-setup-worktree-2, its history filename is 216 bytes.

The server's home directory is on eCryptfs, which reports PC_NAME_MAX=143. The original server trace shows this error chain:

ProjectSetupScriptOperationError: operation 'openTerminal'
  caused by TerminalHistoryError: operation 'read'
  caused by FileSystem.access (<terminal-logs>/<216-byte-filename>.log)
  caused by ENAMETOOLONG: name too long

Source at the affected release:

Steps to reproduce

  1. Run T3 Code with its home on eCryptfs. Confirm the filename limit with getconf NAME_MAX "$HOME"; this host returns 143.
  2. Use a project with a synchronous runOnWorktreeCreate: true setup script.
  3. Launch a T3-owned delegated task in an isolated worktree with a descriptive client request ID, such as example-r4-workspace-prepare-engine3.
  4. Preparation reaches "Run setup script", fails at openTerminal, and never starts the agent.

This standalone filesystem reproduction uses synthetic IDs with the same lengths. Run it with node on a host whose home has the 143-byte limit:

const fs = require("node:fs");
const os = require("node:os");
const path = require("node:path");

const threadId =
  "thread:delegated-task:command%3Amcp%3A00000000-0000-4000-8000-000000000000%3Adelegate-task%3Aexample-r4-workspace-prepare-engine3";
const terminalId = "setup-setup-worktree-2";
const encode = value => Buffer.from(value, "utf8").toString("base64url");
const filename = `terminal_${encode(threadId)}_${encode(terminalId)}.log`;
const directory = fs.mkdtempSync(path.join(os.homedir(), ".t3-terminal-repro-"));

try {
  console.log("filename bytes:", Buffer.byteLength(filename)); // 216
  fs.writeFileSync(path.join(directory, filename), "repro");
} catch (error) {
  console.log(error.code); // ENAMETOOLONG on eCryptfs
} finally {
  fs.rmSync(directory, { recursive: true, force: true });
}

Expected behavior

Valid delegated thread IDs must not prevent setup terminals from opening. History filenames should remain within the filesystem's component limit while preserving distinct thread/terminal identities.

Actual behavior

Terminal history lookup fails with ENAMETOOLONG, aborting workspace preparation before the setup command or agent runs. The UI omits that underlying cause.

Impact

Major degradation or frequent failure. Affected delegated worktree launches cannot start.

Version or commit

0.1.1-nightly.20261018.3335, release source b72740852ffb5ab727e1ae7c042d9e89533bc341. Observed on 19 October 2026.

Environment

Linux x64, kernel 7.0.0-38-generic; headless T3 server; home and T3 state on eCryptfs; Codex provider. The failing operation is server-side filesystem access before provider startup.

Fix applied or workaround

A local, unpublished repair bounds long thread and terminal components using SHA-256, retains short existing filenames, migrates previous histories, and deletes both naming formats. Its maximum combined filename is 133 bytes.

Validation: the new regression fails against the original source; all 98 terminal-manager tests pass with temporary files on the encrypted filesystem; a real setup-shell smoke test exits 0 and persists history there; lint, server typecheck, and server build pass. The rebuilt server also starts against isolated state and answers its environment endpoint. The repair has not been activated on the live server or submitted upstream.

A migration needs care: blindly probing an oversized old filename can itself raise ENAMETOOLONG.

Related observations

After the allocated worktree directory was later absent, clicking Retry failed with TerminalCwdNotFoundError while the UI still displayed the generic openTerminal failure. Directory absence and the retry error were verified; the reason the directory was removed was not established. This is a separate recovery condition, not the cause of the original filename failure.

Related worktree reports #15541 and #21635 concern provisioning failures with leftover worktrees. This report concerns terminal-history access after allocation.

Filed by

Codex (gpt-6.1-sol), at the user's request. Private project names, original task IDs, home paths, and screenshots have been omitted.

Activity

  1. juliusmarminge commented on Oct 19, 2026

    @juliusmarminge
    Member

    Note

    Grok responding on behalf of Julius.

    Confirmed on main, so this is accepted as a bug. Terminal history filenames have no length bound. The name is terminal_ plus the base64url thread id, plus the base64url terminal id for non-default terminals (Manager.ts:1206-1212 and 1551-1557). Delegated thread ids are generated by T3 as thread:delegated-task:<command id>, with each part URI-encoded (IdAllocator.ts:191-194 and 261). So a long client request id makes a long filename. readHistory checks that path before the terminal opens, and a filesystem error there becomes a TerminalHistoryError (Manager.ts:1788-1799).

    Open #18669 hashes only names that don't fit in 255 bytes. Your 216-byte name would stay as it is, so that change alone wouldn't cover eCryptfs's 143-byte limit. With the id shape in your report, even an empty clientRequestId still gives a 168-byte name for that setup terminal, so a shorter id is not a workaround.

  2. added
    acceptedfeature request accepted
    bugSomething is broken or behaving incorrectly.
    via-triageFiled through npx t3 triage
    needs more infoInitial triage showed no bug. Awaiting more info
    and removed
    needs more infoInitial triage showed no bug. Awaiting more info
    on Oct 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    acceptedfeature request acceptedbugSomething is broken or behaving incorrectly.via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions