Crosstalk-Solutions/project-nomad · error · Error
Storage drive not available: cannot write to ${STORAGE_BASE}
Error message
Storage drive not available: cannot write to ${STORAGE_BASE} (${mkdirErr instanceof Error ? mkdirErr.message : String(mkdirErr)}) What it means
Thrown by verifyStorageAvailable in the FDA drug data download job when the storage directory is neither writable nor creatable. It first tries access(STORAGE_BASE, W_OK); on failure it attempts mkdir recursive, and if that also fails it marks the job phase 'failed' and throws this error with the underlying mkdir failure message.
Source
Thrown at admin/app/jobs/download_drug_data_job.ts:287
await IngestDrugDataJob.dispatch(resourceMeta)
logger.info('[DownloadDrugDataJob] Auto-chained ingest phase')
}
}
return { partIndex, totalParts }
}
// ─── Private helpers ───────────────────────────────────────────────────────
private async verifyStorageAvailable(job: Job): Promise<void> {
try {
await access(STORAGE_BASE, constants.W_OK)
} catch {
try {
await mkdir(STORAGE_BASE, { recursive: true })
} catch (mkdirErr) {
await job.updateData({ ...job.data, phase: 'failed' })
throw new Error(
`Storage drive not available: cannot write to ${STORAGE_BASE} (${
mkdirErr instanceof Error ? mkdirErr.message : String(mkdirErr)
})`
)
}
}
}
private async fetchManifest(): Promise<DrugLabelManifest> {
return DownloadDrugDataJob.fetchManifest()
}
/**
* Fetch + parse the openFDA download manifest. The SINGLE source of truth for
* the openFDA manifest call (Maxim 4): the download job uses it on pass 0, and
* the freshness check (DrugReferenceService.checkForUpdate, driven by
* attemptAutoUpdate) reuses it so there is exactly one place that knows the URL and the
* offline-error translation.View on GitHub (pinned to 0bd1c6f4f9)
Solutions
- Check the mount and permissions: ls -ld $STORAGE_BASE and df -h; remount or free the volume.
- Fix ownership/permissions so the app user can write: chown/chmod the directory or the parent path.
- Verify Docker volume mounts if containerized — ensure the host path exists and is writable by the container user.
- If STORAGE_BASE is configurable, confirm it isn't pointing at a stale or unplugged drive path.
Example fix
# shell ls -ld "$STORAGE_BASE" # check perms sudo chown -R appuser:appgroup "$STORAGE_BASE" # or fix the env STORAGE_BASE=/data/fda
Defensive patterns
Strategy: validation
Validate before calling
import { access, constants } from 'node:fs/promises'
async function storageWritable(base: string): Promise<boolean> {
try {
await access(base, constants.W_OK)
return true
} catch {
try { await mkdir(base, { recursive: true }); return true } catch { return false }
}
}
// call before enqueuing the download job
if (!(await storageWritable(process.env.STORAGE_BASE!))) {
// surface UI error instead of enqueuing
} Try / catch
catch (err) {
if (err instanceof Error && err.message.startsWith('Storage drive not available')) {
// show 'check storage drive' to user; do not retry automatically
}
throw err
} Prevention
- Health-check STORAGE_BASE writability at app startup, not just in the job.
- Monitor disk space and mount status for the storage volume.
- Ensure the service user owns STORAGE_BASE in deployment scripts.
When it happens
Trigger: STORAGE_BASE points to a read-only mount, a path whose parent is not writable, a full disk, or a missing drive (e.g. unplugged USB/external storage). Any run of the DownloadDrugDataJob whose handle() calls verifyStorageAvailable() under these conditions.
Common situations: Running the app on a device where the storage volume is unmounted, Docker container with a missing/bind-mounted volume, permission mismatch between app user and directory owner, SELinux/AppArmor denials, disk full.
Related errors
- Failed to read file stream: ${filename}
- Error scanning and syncing storage
- No internet — connect to download FDA drug data. (${msg})
- File not found: ${filename}
- Base map assets are missing and could not be downloaded. Ple
AI-assisted analysis of Crosstalk-Solutions/project-nomad@0bd1c6f4f9 (2026-08-27).
Data as JSON: /api/errors/202d2743f0f520ee.
Report an issue: GitHub.