windmill-labs/windmill · warning

Could not open Claude Desktop deep link (${err.message}). Op

Error message

Could not open Claude Desktop deep link (${err.message}). Open it manually: ${deepLink}

What it means

Warning emitted by `wmill app new` after scaffolding, when it tries to resume/import the freshly created Claude session in Claude Desktop via the macOS `open` command with a claude:// deep link. The execFile('open', [deepLink]) callback received an error, meaning macOS failed to hand the URL to the Claude Desktop app (e.g. `open` binary missing/failed or no app registered for the claude:// scheme). The CLI suggests opening the printed deep link manually and continues.

Source

Thrown at cli/src/commands/app/new.ts:864

              { cwd: absAppDir },
              (error) => (error ? reject(error) : resolve())
            );
          });
        } finally {
          // On exec rejection control jumps to the outer catch — without this
          // finally the spinner keeps writing to stdout and garbles output.
          clearInterval(spinner);
          process.stdout.write("\r" + " ".repeat(40) + "\r");
        }

        // Import the session into Claude Desktop Code mode. Use execFile so
        // the deep link doesn't pass through a shell — `sessionId` is a UUID
        // and absAppDir is URI-encoded inside the URL today, but execFile
        // removes shell escaping concerns entirely.
        const deepLink = `claude://resume?session=${sessionId}&cwd=${encodeURIComponent(absAppDir)}`;
        execFile("open", [deepLink], (err) => {
          if (err) {
            log.warn(
              colors.yellow(
                `Could not open Claude Desktop deep link (${err.message}). Open it manually: ${deepLink}`
              )
            );
          } else {
            log.info(colors.bold.green("Opened in Claude Desktop!"));
          }
        });
      } catch (error: unknown) {
        const errorMessage =
          error instanceof Error ? error.message : String(error);
        log.warn(
          colors.yellow(
            `Could not open in Claude Desktop: ${errorMessage}`
          )
        );
        log.info(
          colors.gray(

View on GitHub (pinned to e474e8803c)

Solutions

  1. Open the printed deep link manually (copy `claude://resume?session=...&cwd=...` into a browser or Spotlight) to resume the session in Claude Desktop.
  2. Verify Claude Desktop is installed and launched at least once so it registers the claude:// scheme, then retry `wmill app new`.
  3. Test the handler manually: run `open 'claude://resume'` in a terminal; if it fails, re-install or re-launch Claude Desktop.
  4. As a fallback, run `cd <appDir> && claude` in the terminal, which the CLI also suggests on the sibling error path.

Example fix

// before (inside the CLI's callback path)
execFile("open", [deepLink], (err) => { if (err) log.warn(...); });
// after (caller-side manual fallback)
execFile("open", [deepLink], (err) => {
  if (err) {
    console.log(`Open manually: ${deepLink}`);
    // or: execFile("xdg-open", [deepLink]) on Linux
  }
});
Defensive patterns

Strategy: try-catch

Validate before calling

import { execFile } from "node:child_process";
function canOpenDeepLinks(): Promise<boolean> {
  return new Promise((res) =>
    execFile("open", ["-Ra", "Claude"], (err) => res(!err))
  );
}

Type guard

function isExecFileError(e: NodeJS.ErrnoException | null): e is NodeJS.ErrnoException & { code: string } {
  return e !== null && typeof e.code === "string";
}

Try / catch

execFile("open", [deepLink], (err) => {
  if (err) {
    log.warn(`Deep link failed (${err.message}); open manually: ${deepLink}`);
  } else {
    log.info("Opened in Claude Desktop!");
  }
});

Prevention

When it happens

Trigger: Running `wmill app new` on macOS with Claude Desktop detected, answering 'Open in Claude Desktop?', and execFile('open', [deepLink]) invokes its callback with an error: `open` not found or non-zero exit (no handler registered for claude://, Claude Desktop uninstalled/deregistered, or headless environment without a GUI session).

Common situations: Claude Desktop installed but its URL handler deregistered after an update; running over SSH without a GUI login session; macOS security prompts blocking `open`; user on Linux where /usr/bin/open is not macOS's open (e.g. openstructure) and cannot handle claude://.

Related errors


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/712ccf9746760eb9. Report an issue: GitHub.