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

  1. Re-run the export — transient Lokalise issues often clear on retry.
  2. Inspect the full processResult JSON in the error to find the URL under a different field, and update the bundleUrl extraction.
  3. 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

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


AI-assisted analysis of tldraw/tldraw@b31086b447 (2026-08-12). Data as JSON: /api/errors/2c0338a6da6cbac3. Report an issue: GitHub.