can1357/oh-my-pi · error · Error
Could not resolve ${APP_NAME} launcher path in PATH
Error message
Could not resolve ${APP_NAME} launcher path in PATH What it means
A defensive guard in the bun/npm self-update branch: when a forced binary takeover is requested but the update target's launcher filesystem path is unknown, the code refuses to proceed rather than overwrite an unknown file. The comment notes this is only reachable on Windows, where a script launcher resolved from PATH may lack a recorded path because bin-dir probes are skipped in forced mode.
Source
Thrown at packages/coding-agent/src/cli/update-cli.ts:2015
const target = await resolveUpdateTarget({ allowPackageManagers: !forceBinary });
if (channel === "canary" && (target.method === "nix" || target.method === "brew" || target.method === "mise")) {
console.log(chalk.yellow("Canary updates are only supported for bun, npm, or binary installs."));
return;
}
if (target.method === "nix") {
console.log(chalk.yellow("This installation is managed by Nix and cannot update itself."));
console.log(chalk.dim("Update the flake input or profile that provides omp, then rebuild."));
return;
} else if (target.method === "brew") {
await updateViaHomebrew(release.version, opts.force);
} else if (target.method === "mise") {
await updateViaMise(release.version, opts.force);
} else if (target.method === "bun" || target.method === "npm") {
if (forceBinary) {
// Reachable in forced mode only through a Windows script
// launcher resolved from PATH (the bun/npm bin-dir probes are
// skipped), so the launcher path is always known.
if (!target.path) throw new Error(`Could not resolve ${APP_NAME} launcher path in PATH`);
console.log(chalk.dim("This release ships as a standalone binary; replacing the script launcher."));
await updateViaShimTakeover(target.path, release.version, { allowPrerelease });
console.log(
chalk.yellow(
`This install is no longer managed by ${target.method}. Removing the old global package may delete this launcher; if it does, reinstall with: ${installerHint()}`,
),
);
} else {
await updateViaManager(
release,
target.path,
packageManagerUpdateSteps(target.method, release, allowPrerelease),
);
}
} else {
if (forceBinary && target.replacesSymlink) {
console.log(chalk.dim("Replacing the package-manager launcher with the standalone binary."));
}View on GitHub (pinned to 9690622007)
Solutions
- Run the update without forced-binary mode so the normal probe path resolves the launcher
- Locate the launcher manually (`where omp` / `Get-Command omp` in PowerShell) and install the standalone binary over it yourself
- Reinstall via bun/npm so the launcher sits in a standard bin dir the probes can find
- Check PATH for non-standard entries and normalize them before updating
Example fix
// before (crashes on unknown path)
if (!target.path) throw new Error(`Could not resolve ${APP_NAME} launcher path in PATH`);
await updateViaShimTakeover(target.path, release.version, { allowPrerelease });
// after (resolve path explicitly first)
const launcherPath = target.path ?? (await resolveLauncherFromPath(APP_NAME));
if (!launcherPath) throw new Error(`Could not resolve ${APP_NAME} launcher path in PATH`);
await updateViaShimTakeover(launcherPath, release.version, { allowPrerelease }); Defensive patterns
Strategy: validation
Validate before calling
import { $which } from "@oh-my-pi/pi-utils";
const launcher = await $which(APP_NAME);
if (!launcher) throw new Error(`${APP_NAME} not found on PATH; cannot force binary takeover`); Type guard
function hasLauncherPath(t: UpdateTarget): t is UpdateTarget & { path: string } {
return typeof t.path === "string" && t.path.length > 0;
} Try / catch
try {
await updateSelf({ forceBinary: true });
} catch (err) {
if (err.message.includes("Could not resolve") || err.message.includes("launcher path")) {
// resolve launcher manually (`where omp`) and reinstall standalone binary
} else throw err;
} Prevention
- On Windows, keep the CLI's shim inside bun/npm's standard bin dir so probes find it
- Avoid forcing binary mode when the install origin is ambiguous
- Check `Get-Command omp` before forced updates to confirm the launcher location
When it happens
Trigger: Running forced self-update (--force-binary style) on a bun/npm install where target.method is bun or npm and target.path is undefined — practically only on Windows when the launcher was found via PATH lookup instead of the bun/npm bin-dir probes.
Common situations: Windows installs where the shim lives in a directory outside the detected bun/npm bin dirs (custom PATH entry, alternate install location); heavily customized PATH setups.
Related errors
- ${steps.manager} update did not produce a working launcher a
- cannot access {}: Not a directory
- invalid template, {}; with --tmpdir, it may not be absolute
- failed to access {0}: Not a directory
- can't determine symlink type, since it is dangling
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/f2f23de06fd463d5.
Report an issue: GitHub.