tldraw/tldraw · error · Error
Async export finished but no bundle URL was returned: ${JSON
Error message
Async export finished but no bundle URL was returned: ${JSON.stringify(processResult, null, 2)} What it means
When the async export process reaches status 'finished', the code expects details.download_url or details.bundle_url. Throws if both are absent on a finished process — Lokalise marked it done but returned no downloadable bundle.
Source
Thrown at internal/scripts/i18n-download-strings.ts:84
throw new Error(`Async export did not return process_id: ${JSON.stringify(start, null, 2)}`)
}
for (let i = 0; i < ASYNC_EXPORT_MAX_POLLS; i++) {
const processResult = await lokaliseRequest<{
process?: {
status?: string
message?: string
details?: { download_url?: string; bundle_url?: string }
}
}>(`/projects/${projectId}/processes/${start.process_id}`, { method: 'GET' }, apiKey)
const status = processResult.process?.status
const details = processResult.process?.details
const bundleUrl = details?.download_url ?? details?.bundle_url
if (status === 'finished') {
if (!bundleUrl) {
throw new Error(
`Async export finished but no bundle URL was returned: ${JSON.stringify(processResult, null, 2)}`
)
}
return bundleUrl
}
if (status === 'failed' || status === 'cancelled') {
throw new Error(
`Async export ${status}: ${processResult.process?.message ?? 'No message'}\n${JSON.stringify(processResult, null, 2)}`
)
}
await sleep(ASYNC_EXPORT_POLL_INTERVAL_MS)
}
throw new Error(
`Async export timed out after ${ASYNC_EXPORT_MAX_POLLS} polls for project ${projectId}`
)View on GitHub (pinned to b31086b447)
Solutions
- Re-run the export — transient Lokalise issues often clear on retry.
- Inspect the full processResult JSON in the error to find the URL under a different field, and update the bundleUrl extraction.
- Confirm the project actually has files to export (empty project → no bundle).
Example fix
// before const bundleUrl = details?.download_url ?? details?.bundle_url // after (also accept a top-level url) const bundleUrl = details?.download_url ?? details?.bundle_url ?? processResult.process?.url
Defensive patterns
Strategy: type-guard
Validate before calling
const bundleUrl = details?.download_url ?? details?.bundle_url ?? (processResult as any).process?.url
if (!bundleUrl) throw new Error('No bundle URL field on finished process') Type guard
function hasBundleUrl(details: unknown): details is { download_url?: string; bundle_url?: string } {
return Boolean((details as any)?.download_url || (details as any)?.bundle_url)
} Prevention
- Inspect full processResult JSON on failure to discover renamed fields.
- Retry once on missing bundle URL — transient Lokalise issue.
- Confirm the project has files before exporting.
When it happens
Trigger: Lokalise bug returning finished status with empty details; the export produced an empty file set and Lokalise omitted the URL; response schema change relocating the URL field.
Common situations: Transient Lokalise-side issue; project with no files matching the filter; API version returning the URL under a different key.
Related errors
- Async export did not return process_id: ${JSON.stringify(sta
- Lokalise request failed (${response.status}): ${JSON.stringi
- Async export ${status}: ${processResult.process?.message ??
- Async export timed out after ${ASYNC_EXPORT_MAX_POLLS} polls
- Upload did not return a process_id: ${JSON.stringify(uploadR
AI-assisted analysis of tldraw/tldraw@b31086b447 (2026-08-12).
Data as JSON: /api/errors/2c0338a6da6cbac3.
Report an issue: GitHub.