tinyhumansai/openhuman · error

DOWNLOAD_FAILED

DOWNLOAD_FAILED

Error message

${reason}

What it means

Returned by downloadArtifact when the Tauri IPC command download_artifact_to_downloads throws after the artifact had already resolved successfully (resolveArtifactForExport returned ok). The copy happens inside the Rust shell, so the failure is native: the source blob vanished, the Downloads destination is missing or unwritable, the disk is full, or the invoke ran outside a real Tauri context. The JS side wraps the raw invoke error message as DOWNLOAD_FAILED.

Source

Thrown at app/src/services/artifactDownloadService.ts:256

      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 };
  }
}

/**
 * Export an artifact via the native Save-As dialog (#3162), pre-filled
 * with the artifact's filename. On the user dismissing the dialog,
 * returns `{ ok: false, code: 'CANCELLED' }` (the caller should treat
 * this as a no-op, not an error). If the dialog itself is unavailable —
 * e.g. headless Linux with no xdg-desktop portal — falls back to the
 * Downloads copy so the artifact is still recoverable.
 */
export async function saveArtifactViaDialog(
  artifactId: string,
  fallbackTitle: string,
  extension: string
): Promise<DownloadArtifactOutcome> {
  if (!isTauri()) {
    return { ok: false, code: 'NOT_DESKTOP', error: 'Saving is only available in the desktop app' };

View on GitHub (pinned to 7491200858)

Solutions

  1. Read the outcome's error field - it is the raw Tauri command error and distinguishes 'source file missing' from permission or full-disk failures.
  2. If the source blob is gone, call deleteArtifact(artifactId) to drop the stale ArtifactMeta row, then regenerate the artifact.
  3. Confirm you are inside the Tauri desktop shell (`pnpm dev:app` or a built app) and that ~/Downloads exists and is writable.
  4. Fall back to revealArtifactInFileManager, or re-run generation when the copy keeps failing.

Example fix

// before
const out = await downloadArtifact(id, title, ext);
if (!out.ok) showError('Download failed'); // collapses every code into one message

// after
const out = await downloadArtifact(id, title, ext);
if (!out.ok) {
  if (out.code === 'DOWNLOAD_FAILED' && /no such file|not found/i.test(out.error ?? '')) {
    await deleteArtifact(id); // stale row: blob already gone
    showError('Artifact file is missing. Regenerating.');
  } else {
    showError(`Download failed: ${out.error}`);
  }
}
Defensive patterns

Strategy: fallback

Try / catch

downloadArtifact never throws - it returns a DownloadArtifactOutcome. Branch on code: DOWNLOAD_FAILED with a file-missing reason -> offer delete-and-regenerate or revealArtifactInFileManager as fallback; other codes -> surface the error text verbatim.

Prevention

When it happens

Trigger: Calling downloadArtifact(artifactId) where resolveArtifactForExport succeeds but invoke('download_artifact_to_downloads', { sourcePath, filename }) rejects: the on-disk artifact file was deleted or moved after its ArtifactMeta row was registered, ~/Downloads is absent or read-only, the volume is full, or the frontend runs in a plain browser where the command cannot resolve.

Common situations: A stale artifact row still listed in the UI while another flow or the user already removed its file; macOS privacy permissions denying Downloads writes; running the UI via `pnpm dev` (browser only) instead of `pnpm dev:app`; full disks on long-lived machines.

Related errors


AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17). Data as JSON: /api/errors/c6f4e61d422ddd28. Report an issue: GitHub.