{"record":{"id":"77d04ff95ff7f7a8","repo":"different-ai/openwork","slug":"result","errorCode":null,"errorMessage":"${result}","messagePattern":"\\$\\{result\\}","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/app/src/app/lib/desktop.ts","lineNumber":501,"sourceCode":"export async function openDesktopUrl(url: string): Promise<void> {\n  const safeUrl = assertDesktopWebUrl(url);\n  const openExternal = window.__OPENWORK_ELECTRON__?.shell?.openExternal;\n  if (openExternal) {\n    const result = await openExternal(safeUrl);\n    if (result && result.ok === false) {\n      throw new Error(result.error ?? \"Failed to open browser\");\n    }\n    return;\n  }\n  if (typeof window !== \"undefined\") {\n    window.open(safeUrl, \"_blank\", \"noopener,noreferrer\");\n  }\n}\n\nexport async function openDesktopPath(target: string): Promise<void> {\n  const result = await invokeElectronHelper(\"__openPath\", target);\n  if (typeof result === \"string\" && result.trim()) {\n    throw new Error(result);\n  }\n}\n\nexport async function revealDesktopItemInDir(target: string): Promise<void> {\n  const result = await invokeElectronHelper(\"__revealItemInDir\", target);\n  if (typeof result === \"string\" && result.trim()) {\n    throw new Error(result);\n  }\n}\n\nexport async function getDesktopFileIcon(target: string, size?: \"small\" | \"normal\" | \"large\"): Promise<string | null> {\n  return invokeElectronHelper(\"__getFileIcon\", target, size);\n}\n\nexport async function applyBrandAppName(appName: string | null): Promise<string> {\n  const result = await invokeElectronHelper(\"__applyBrandAppName\", appName);\n  return result.appName;\n}","sourceCodeStart":483,"sourceCodeEnd":519,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/apps/app/src/app/lib/desktop.ts#L483-L519","documentation":"openDesktopPath forwards the `__openPath` command to the Electron bridge, which returns a string error description on failure (empty string on success). Any non-empty result is thrown as-is, so the message text comes from the main process — typically the OS failing to open the file/folder with its default handler.","triggerScenarios":"invokeElectronHelper(\"__openPath\", target) returning a non-empty string, i.e. the main process could not open `target` — path does not exist, no default application for the file type, or permission denied.","commonSituations":"Opening a config/workspace file that was deleted or moved after the UI listed it; a file type with no associated app on the machine (e.g. a dotfile on a fresh Linux install); a path on an unmounted drive or network share; a project dir opened via a stale symlink.","solutions":["Verify the target path exists and is accessible (`await fs.access(path)` / ls the path) before calling openDesktopPath; refresh the file listing if it is stale.","Associate a default application for the file type in the OS, or use openDesktopWithApp to pick an explicit app.","If the intent is just to show the file's folder, call revealDesktopItemInDir instead, which only needs the parent directory.","Read the thrown message (from the main process) for the exact OS reason — ENOENT vs no handler vs EACCES — and fix accordingly."],"exampleFix":"// before\nawait openDesktopPath(projectConfigPath);\n\n// after\nif (!(await exists(projectConfigPath))) {\n  showToast(\"File no longer exists\");\n  return;\n}\nawait openDesktopPath(projectConfigPath);","handlingStrategy":"validation","validationCode":"async function pathExists(p: string): Promise<boolean> {\n  try { await fs.promises.access(p); return true; } catch { return false; }\n}\n// call: if (!(await pathExists(target))) return showToast(\"File not found\");","typeGuard":null,"tryCatchPattern":"try {\n  await openDesktopPath(target);\n} catch (err) {\n  showToast(`Could not open item: ${err instanceof Error ? err.message : err}`);\n}","preventionTips":["Check file existence before offering open actions in the UI.","Refresh file listings after rename/delete operations so stored paths stay current.","Prefer openDesktopWithApp or revealDesktopItemInDir when no default handler exists for a type.","Surface the propagated OS error message to the user instead of swallowing it."],"tags":["electron","filesystem","desktop-integration","path-errors"],"backgroundTag":"open-path-failed","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}