{"record":{"id":"c232cc492940a626","repo":"tinyhumansai/openhuman","slug":"not-desktop","errorCode":"NOT_DESKTOP","errorMessage":"Downloads are only available in the desktop app","messagePattern":"Downloads are only available in the desktop app","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"info","filePath":"app/src/services/artifactDownloadService.ts","lineNumber":238,"sourceCode":"  // requested extension (case-insensitive, with any other extension also\n  // tolerated), don't append again. Prevents `deck.pptx.pptx` when the\n  // persisted title is `deck.pptx` and the caller passes `'pptx'`.\n  const titleHasExtension = /\\.[^./\\\\]+$/.test(title);\n  const titleHasSameExt = ext.length > 0 && title.toLowerCase().endsWith(`.${ext.toLowerCase()}`);\n  const filename = ext && !titleHasExtension && !titleHasSameExt ? `${title}.${ext}` : title;\n\n  return { ok: true, sourcePath, filename };\n}\n\nexport async function downloadArtifact(\n  artifactId: string,\n  fallbackTitle: string,\n  extension: string\n): Promise<DownloadArtifactOutcome> {\n  if (!isTauri()) {\n    return {\n      ok: false,\n      code: 'NOT_DESKTOP',\n      error: 'Downloads are only available in the desktop app',\n    };\n  }\n\n  const resolved = await resolveArtifactForExport(artifactId, fallbackTitle, extension);\n  if (!resolved.ok) {\n    return { ok: false, code: resolved.code, error: resolved.error };\n  }\n\n  try {\n    const dest = await invoke<string>('download_artifact_to_downloads', {\n      sourcePath: resolved.sourcePath,\n      filename: resolved.filename,\n    });\n    return { ok: true, path: dest };\n  } catch (err) {\n    const reason = err instanceof Error ? err.message : String(err);\n    return { ok: false, code: 'DOWNLOAD_FAILED', error: reason };","sourceCodeStart":220,"sourceCodeEnd":256,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/app/src/services/artifactDownloadService.ts#L220-L256","documentation":"downloadArtifact first checks isTauri(); in a plain browser context (Vite dev server at pnpm dev, or a web deployment) there is no Tauri shell to invoke the 'download_artifact_to_downloads' command, so it returns { ok: false, code: 'NOT_DESKTOP', error: 'Downloads are only available in the desktop app' } without attempting any RPC. This is an environment capability gate, not a failure - it fires deterministically whenever the same UI runs outside the desktop host.","triggerScenarios":"Opening the app in a browser via the Vite dev server instead of the Tauri shell (pnpm dev vs pnpm dev:app), or any web-only deployment, then clicking an artifact download / Save-As affordance.","commonSituations":"Frontend development in the browser where core RPC proxies exist over HTTP but Tauri invoke() does not; testing shared components in Storybook/Vitest (jsdom has no Tauri); users hitting a hosted preview of the UI.","solutions":["Run the full desktop app (pnpm dev:app / installed build) for download flows","In UI code, hide or disable download buttons when !isTauri() so the state is unreachable","Treat the code field, not the message string, as the branch condition if you need to react to it"],"exampleFix":"// before - always render the download button\n<DownloadButton onClick={() => void downloadArtifact(id, title, 'md')} />\n\n// after - only offer it where it can work\n{isTauri() && (\n  <DownloadButton onClick={() => void downloadArtifact(id, title, 'md')} />\n)}","handlingStrategy":"type-guard","validationCode":"// Gate the affordance on the environment before the service is called\nimport { isTauri } from '<tauri guard util>';\nif (!isTauri()) {\n  // hide the download button or show 'desktop app only' hint\n}","typeGuard":"const isDesktop = (): boolean => isTauri();\n\n// NOT_DESKTOP is deterministic outside Tauri - the type guard IS the environment check\nconst isNotDesktop = (o: DownloadArtifactOutcome): o is { ok: false; code: 'NOT_DESKTOP'; error: string } =>\n  !o.ok && o.code === 'NOT_DESKTOP';","tryCatchPattern":null,"preventionTips":["Use isTauri() (never window.__TAURI__) to conditionalize desktop-only affordances at render time","Run pnpm dev:app rather than pnpm dev when exercising download/export flows","Branch on the code field ('NOT_DESKTOP'), not the human-readable message, if you must react to it"],"tags":["artifacts","tauri","environment-check","desktop-only","is-tauri"],"backgroundTag":"platform-capability-unavailable","analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}