Skip to content

[Bug]: service install/update cannot find service-launcher.mjs when CLI is invoked through a symlink #5196

Description

@Destreyf

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

Steps to reproduce

  1. On Linux with systemd, install the t3 CLI globally through a Node version manager/package-manager setup where the t3 executable is a symlink to the package's real dist/bin.mjs entry point. This was reproduced with mise and a global npm package.

  2. Run either:

    t3 service install

    or:

    t3 service update
  3. The command fails while trying to copy service-launcher.mjs into the managed runtime.

The published package does contain service-launcher.mjs next to the real dist/bin.mjs. The failure occurs because the lookup is based on the unresolved symlink invocation path.

Expected behavior

The CLI should resolve its packaged launcher relative to the real CLI entry point and install or update the background service successfully, regardless of whether the executable was invoked through a package-manager or version-manager symlink.

Actual behavior

The CLI looks for service-launcher.mjs beside the symlink in the global executable directory instead of beside the real dist/bin.mjs, then fails with BootServiceInstallError / ENOENT.

The relevant implementation sets cliEntryPath from HostProcessArguments[1] and derives launcherSourcePath using dirname(cliEntryPath). Node preserves the symlink used for invocation in process.argv[1], so the derived directory is not necessarily the package's real dist directory.

This appears to have been introduced with commit d3037064e6, which added the packaged service-launcher lookup. It is confirmed in 0.0.32-nightly.20260801.974, and current main still contains the unresolved lookup. Earlier update failures may have other causes; this report intentionally does not claim that earlier releases had this exact failure.

Impact

Major degradation or frequent failure

Version or commit

Confirmed in 0.0.32-nightly.20260801.974; also present on current main

Environment

Linux with systemd, Node.js 24.18.0, mise-managed Node installation, globally installed npm CLI

Logs or stack traces

BootServiceInstallError: Could not set up the T3 Code background service.
  [cause]: PlatformError: NotFound: FileSystem.readFile (<global-executable-directory>/service-launcher.mjs)
    [cause]: Error: ENOENT: no such file or directory, open '<global-executable-directory>/service-launcher.mjs'

No user-specific paths are required to reproduce the issue. The launcher is present beside the real package entry point; only the symlink-relative lookup is missing it.

Workaround

Resolve the CLI symlink before invoking the command so process.argv[1] is the real package entry point:

node "$(realpath "$(command -v t3)")" service install

For an existing service that needs an update or repair:

node "$(realpath "$(command -v t3)")" service update

Both commands avoid adding or copying files into the global executable directory.

Suggested fix

Resolve cliEntryPath through the filesystem before deriving launcherSourcePath, or derive the launcher location from a module-relative URL that refers to the packaged dist directory. A regression test should invoke the CLI entry through a symlink and verify that installation reads the launcher beside the symlink target.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions