jackwener/OpenCLI · error · CliError
DOWNLOAD_ERROR
DOWNLOAD_ERROR
Error message
DOWNLOAD_ERROR
What it means
DOWNLOAD_ERROR is thrown by downloadOutput when the fetch of the generated result URL returns a non-ok HTTP status. Result URLs on the host are typically signed/expiring, so a failed download usually means the link is no longer valid. The file is never written when this throws.
Source
Thrown at clis/yollomi/utils.js:98
if (!fs.existsSync(resolved)) {
throw new CliError('FILE_NOT_FOUND', `File not found: ${resolved}`, 'Provide a valid file path or URL');
}
const ext = path.extname(resolved).toLowerCase();
const mimeMap = {
'.jpg': 'image/jpeg', '.jpeg': 'image/jpeg',
'.png': 'image/png', '.gif': 'image/gif',
'.webp': 'image/webp', '.bmp': 'image/bmp',
};
const mime = mimeMap[ext] || 'image/png';
const data = fs.readFileSync(resolved);
return `data:${mime};base64,${data.toString('base64')}`;
}
export async function downloadOutput(url, outputDir, filename) {
fs.mkdirSync(outputDir, { recursive: true });
const destPath = path.join(outputDir, filename);
const resp = await fetch(url);
if (!resp.ok)
throw new CliError('DOWNLOAD_ERROR', `Download failed: HTTP ${resp.status}`, 'URL may have expired');
const buffer = Buffer.from(await resp.arrayBuffer());
fs.writeFileSync(destPath, buffer);
return { path: destPath, size: buffer.length };
}
export function fmtBytes(bytes) {
if (bytes === 0)
return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return `${(bytes / Math.pow(k, i)).toFixed(1)} ${sizes[i]}`;
}
/** Per-model API route mapping (matches frontend model.apiEndpoint). */
export const MODEL_ROUTES = {
'flux': '/api/ai/flux',
'flux-schnell': '/api/ai/flux-schnell',
'flux-2-pro': '/api/ai/flux-2-pro',
'flux-kontext-pro': '/api/ai/flux-kontext-pro',View on GitHub (pinned to 49907e53dc)
Solutions
- Regenerate the result (rerun the command) to get a fresh URL and download immediately
- Download promptly after generation — do not let signed URLs expire before fetching
- Check the URL for truncation/copy errors if reusing a saved link
- Test the URL in a browser/curl to confirm the HTTP status and whether it is a proxy issue
Example fix
// before
const { url } = previousRunResult;
await downloadOutput(url, out, 'img.png'); // 403: expired
// after
const fresh = await upscale(page, { image }); // regenerate for a new URL
await downloadOutput(fresh.url, out, 'img.png'); // download right away Defensive patterns
Strategy: fallback
Validate before calling
// Pre-check the URL before committing to a download path
const head = await fetch(url, { method: 'HEAD' });
if (!head.ok) throw new Error(`Result URL dead: HTTP ${head.status} — regenerate`); Type guard
null
Try / catch
try {
await downloadOutput(url, outDir, name);
} catch (e) {
if (e.code === 'DOWNLOAD_ERROR') {
console.error(`${e.message} — regenerating to get a fresh URL`);
const fresh = await regenerate();
return downloadOutput(fresh.url, outDir, name);
}
throw e;
} Prevention
- Download immediately after generation; treat URLs as short-lived
- Never persist result URLs for later reuse without re-validating
- Retry the whole generation rather than retrying a dead URL
When it happens
Trigger: downloadOutput(url, outputDir, filename) receives a URL whose fetch responds with 403/404/410 etc. — typically a result URL used after it expired, a truncated/mistyped URL, or the file removed from storage.
Common situations: Saving a result URL from a previous run and reusing it hours later, using --no-download output URLs in later scripts without re-downloading promptly, network proxies rejecting the storage host, or the provider purging old artifacts.
Related errors
- 1point3acres request failed: HTTP ${res.status} ${res.status
- archive snapshots failed: HTTP ${resp.status}
- ${label} returned HTTP ${resp.status} (${url})
- Failed to download grok image ${img.src}${reason}
- Instagram private publish ${stage} failed: ${response.status
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/967643ab1ac689b4.
Report an issue: GitHub.