moeru-ai/airi · warning
[CSV] Export is only supported in browser environments
Error message
[CSV] Export is only supported in browser environments
What it means
exportCsv implements the browser download flow: Blob + URL.createObjectURL + a synthetic anchor click. It feature-detects Blob, document, and URL first; in an environment missing any of them (Node, SSR/prerender, some workers) it warns and returns without producing a file.
Source
Thrown at packages/stage-shared/src/export-csv.ts:16
function quoteField(field: unknown): string {
return `"${String(field).replace(/"/g, '""')}"`
}
function toCsv(rows: Array<Array<unknown>>): string {
return rows
.map(row => row.map(quoteField).join(','))
.join('\n')
}
export function exportCsv(rows: Array<Array<unknown>>, basename: string) {
if (!rows.length)
return
if (typeof Blob === 'undefined' || typeof document === 'undefined' || typeof URL === 'undefined') {
console.warn('[CSV] Export is only supported in browser environments')
return
}
const csv = toCsv(rows)
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' })
const url = URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url
link.download = `${basename}-${Date.now()}.csv`
link.click()
URL.revokeObjectURL(url)
}
View on GitHub (pinned to 677329427f)
Solutions
- Only call exportCsv from browser/user-gesture code paths (click handlers in the renderer)
- For Node or Electron main, write the CSV with node:fs instead of the Blob download flow
- Feature-detect in the caller and hide the export button where unsupported, so users never trigger the silent no-op
Example fix
// before (shared code, runs everywhere)
exportCsv(rows, 'messages')
// after (branch by environment)
import { isBrowser } from './env'
if (isBrowser) {
exportCsv(rows, 'messages')
}
else {
await writeFile('messages.csv', toCsvText(rows), 'utf8')
} Defensive patterns
Strategy: validation
Validate before calling
const canDownloadInBrowser = typeof Blob !== 'undefined' && typeof document !== 'undefined' && typeof URL !== 'undefined'
if (canDownloadInBrowser) {
exportCsv(rows, 'messages')
}
else {
console.warn('CSV download unavailable in this environment')
} Type guard
function isBrowserDownloadEnv(): boolean {
return typeof Blob !== 'undefined' && typeof document !== 'undefined' && typeof URL !== 'undefined'
} Prevention
- Gate export UI (buttons/menu items) on browser environment checks
- Use node:fs writers for main-process/Node export paths
- Cover the export utility with a jsdom test so env regressions surface in CI
When it happens
Trigger: Calling exportCsv during SSR/prerender, in the Electron main process, in a Node script or test runner without DOM globals.
Common situations: A shared utility invoked from a server route during prerender; unit tests executing the module in pure Node; main-process export code reusing a shared helper.
Related errors
AI-assisted analysis of moeru-ai/airi@677329427f (2026-08-18).
Data as JSON: /api/errors/0ca8142b9d74fc65.
Report an issue: GitHub.