{"record":{"id":"58dcf1d99795dd34","repo":"windmill-labs/windmill","slug":"could-not-open-in-claude-desktop-errormessage","errorCode":null,"errorMessage":"Could not open in Claude Desktop: ${errorMessage}","messagePattern":"Could not open in Claude Desktop: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"cli/src/commands/app/new.ts","lineNumber":876,"sourceCode":"        // the deep link doesn't pass through a shell — `sessionId` is a UUID\n        // and absAppDir is URI-encoded inside the URL today, but execFile\n        // removes shell escaping concerns entirely.\n        const deepLink = `claude://resume?session=${sessionId}&cwd=${encodeURIComponent(absAppDir)}`;\n        execFile(\"open\", [deepLink], (err) => {\n          if (err) {\n            log.warn(\n              colors.yellow(\n                `Could not open Claude Desktop deep link (${err.message}). Open it manually: ${deepLink}`\n              )\n            );\n          } else {\n            log.info(colors.bold.green(\"Opened in Claude Desktop!\"));\n          }\n        });\n      } catch (error: unknown) {\n        const errorMessage =\n          error instanceof Error ? error.message : String(error);\n        log.warn(\n          colors.yellow(\n            `Could not open in Claude Desktop: ${errorMessage}`\n          )\n        );\n        log.info(\n          colors.gray(\n            \"You can manually run: cd \" + folderName + \" && claude\"\n          )\n        );\n      }\n    }\n  }\n}\n\nconst command = new Command()\n  .description(\"create a new raw app from a template\")\n  .option(\n    \"--summary <summary:string>\",","sourceCodeStart":858,"sourceCodeEnd":894,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/cli/src/commands/app/new.ts#L858-L894","documentation":"Warning from `wmill app new`'s outer catch around the whole 'Open in Claude Desktop' block. It fires when any awaited step before the deep-link exec fails: writing/seeding .claude/launch.json (mkdir/stat/writeFile errors), or spawning `claude --session-id <uuid> -p ...` to create the session (exec rejection). The CLI prints the error message and tells the user to manually run `cd <folder> && claude`.","triggerScenarios":"`wmill app new` reached the desktop-open step and either (a) the filesystem rejects the launch.json seeding (read-only dir, permission denied on mkdir/writeFile), or (b) the spawned `claude` CLI binary exits non-zero or cannot be spawned (claude not on PATH, command failed), rejecting the wrapped exec promise.","commonSituations":"Claude Code CLI (`claude`) not installed or not on PATH while Claude Desktop is; corrupted npm/bun global install of claude-code; app directory created on a read-only mount; .claude/launch.json exists with restrictive permissions; claude CLI failing auth on first run.","solutions":["Check that the `claude` CLI is installed and works: run `claude --version` and `claude -p 'hi'` in the app folder; install/update Claude Code if missing.","Run the manual fallback the CLI prints: `cd <appFolder> && claude`, then start the preview with `wmill app dev`.","Check filesystem permissions on the new app directory; ensure .claude/launch.json can be created (or create it manually).","If the error came from the claude command itself, read its message (auth/login errors) and run `claude /login` or fix the API key, then retry `wmill app new`.","Use --open-in-desktop=false (or answer No at the prompt) to skip this optional step entirely; app scaffolding is unaffected."],"exampleFix":"// before: failing inside the block\nawait writeFile(launchPath, launchJson, \"utf-8\");\n// after: caller-side guard before running app new\nconst claudeBin = which.sync(\"claude\", { nothrow: true });\nif (!claudeBin) {\n  console.log('claude CLI not found; skipping desktop open (run `cd dir && claude` later).');\n}","handlingStrategy":"try-catch","validationCode":"import { which } from \"@cliffy/command\"; // or check PATH manually\nconst claudeOnPath = !!await new Promise<boolean>((res) =>\n  execFile(\"claude\", [\"--version\"], (err) => res(!err)));\nif (!claudeOnPath) console.warn('claude CLI missing; desktop-open step will fail.');","typeGuard":"function isNodeSystemError(e: unknown): e is NodeJS.ErrnoException {\n  return e instanceof Error && typeof (e as NodeJS.ErrnoException).code === \"string\";\n}","tryCatchPattern":"try {\n  await seedLaunchJson(absAppDir);\n  await createClaudeSession(absAppDir);\n  openDeepLink(sessionId, absAppDir);\n} catch (error) {\n  const msg = error instanceof Error ? error.message : String(error);\n  log.warn(`Could not open in Claude Desktop: ${msg}`);\n  log.info(`Fallback: cd ${folderName} && claude`);\n}","preventionTips":["Install and authenticate the Claude Code CLI (`claude --version`, `claude /login`) before using the desktop-open feature.","Ensure the target app directory is writable so .claude/launch.json seeding succeeds.","Pass --open-in-desktop=false in scripts/CI to skip this optional, environment-dependent step entirely.","Keep Claude Code and Claude Desktop versions in sync to avoid session-creation failures."],"tags":["cli","claude-desktop","claude-cli","spawn-failure","filesystem"],"backgroundTag":"command-not-found","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}