tinyhumansai/openhuman · info
NOT_DESKTOP
NOT_DESKTOP
Error message
Downloads are only available in the desktop app
What it means
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.
Source
Thrown at app/src/services/artifactDownloadService.ts:238
// requested extension (case-insensitive, with any other extension also
// tolerated), don't append again. Prevents `deck.pptx.pptx` when the
// persisted title is `deck.pptx` and the caller passes `'pptx'`.
const titleHasExtension = /\.[^./\\]+$/.test(title);
const titleHasSameExt = ext.length > 0 && title.toLowerCase().endsWith(`.${ext.toLowerCase()}`);
const filename = ext && !titleHasExtension && !titleHasSameExt ? `${title}.${ext}` : title;
return { ok: true, sourcePath, filename };
}
export async function downloadArtifact(
artifactId: string,
fallbackTitle: string,
extension: string
): Promise<DownloadArtifactOutcome> {
if (!isTauri()) {
return {
ok: false,
code: 'NOT_DESKTOP',
error: 'Downloads are only available in the desktop app',
};
}
const resolved = await resolveArtifactForExport(artifactId, fallbackTitle, extension);
if (!resolved.ok) {
return { ok: false, code: resolved.code, error: resolved.error };
}
try {
const dest = await invoke<string>('download_artifact_to_downloads', {
sourcePath: resolved.sourcePath,
filename: resolved.filename,
});
return { ok: true, path: dest };
} catch (err) {
const reason = err instanceof Error ? err.message : String(err);
return { ok: false, code: 'DOWNLOAD_FAILED', error: reason };View on GitHub (pinned to 7491200858)
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
Example fix
// before - always render the download button
<DownloadButton onClick={() => void downloadArtifact(id, title, 'md')} />
// after - only offer it where it can work
{isTauri() && (
<DownloadButton onClick={() => void downloadArtifact(id, title, 'md')} />
)} Defensive patterns
Strategy: type-guard
Validate before calling
// Gate the affordance on the environment before the service is called
import { isTauri } from '<tauri guard util>';
if (!isTauri()) {
// hide the download button or show 'desktop app only' hint
} Type guard
const isDesktop = (): boolean => isTauri();
// NOT_DESKTOP is deterministic outside Tauri - the type guard IS the environment check
const isNotDesktop = (o: DownloadArtifactOutcome): o is { ok: false; code: 'NOT_DESKTOP'; error: string } =>
!o.ok && o.code === 'NOT_DESKTOP'; Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Model testing is only available in the desktop app.
- Restart Core is only available in the desktop app.
- Not running in Tauri
- Not running in Tauri
- Core RPC token unavailable in Tauri; local RPC auth cannot b
AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17).
Data as JSON: /api/errors/c232cc492940a626.
Report an issue: GitHub.