Crosstalk-Solutions/project-nomad · error · Error
Base map assets are missing from storage/maps
Error message
Base map assets are missing from storage/maps
What it means
generateStylesJSON builds the styles response from base map assets in storage/maps (sprites, fonts, world basemap style fragments). It first checks checkBaseAssetsExist(); if those base files are absent it refuses to generate styles, since the output would reference missing resources.
Source
Thrown at admin/app/services/map_service.ts:349
const response = await axios.head(url)
if (response.status !== 200) {
throw new Error(`Failed to fetch file info: ${response.status} ${response.statusText}`)
}
const contentLength = response.headers['content-length']
const size = contentLength ? parseInt(contentLength.toString(), 10) : 0
return { filename, size }
} catch (error: any) {
logger.error({ err: error }, '[MapService] Preflight check failed for URL')
return { message: 'Preflight check failed. Please verify the URL is valid and accessible.' }
}
}
async generateStylesJSON(host: string | null = null, protocol: string = 'http'): Promise<BaseStylesFile> {
if (!(await this.checkBaseAssetsExist())) {
throw new Error('Base map assets are missing from storage/maps')
}
const baseStylePath = join(this.baseDirPath, this.baseStylesFile)
const baseStyle = await getFile(baseStylePath, 'string')
if (!baseStyle) {
throw new Error('Base styles file not found in storage/maps')
}
const rawStyles = JSON.parse(baseStyle.toString()) as BaseStylesFile
const regions = (await this.listRegions()).files
/** If we have the host, use it to build public URLs, otherwise we'll fallback to defaults
* This is mainly useful because we need to know what host the user is accessing from in order to
* properly generate URLs in the styles file
* e.g. user is accessing from "example.com", but we would by default generate "localhost:8080/..." so maps would
* fail to load.
*/View on GitHub (pinned to 0bd1c6f4f9)
Solutions
- Run the base asset provisioning (ensureBaseAssets/ensureWorldBasemap, or your app's setup command) so storage/maps is populated
- Verify mapStoragePath config points to the directory containing the base assets
- Restore assets from backup or bake them into the container image if network provisioning is unreliable
Example fix
// before const styles = await mapService.generateStylesJSON(host) // after await mapService.ensureBaseAssets() // provision once at startup const styles = await mapService.generateStylesJSON(host)
Defensive patterns
Strategy: fallback
Validate before calling
if (!(await mapService.checkBaseAssetsExist(false))) { await mapService.ensureBaseAssets() }
const styles = await mapService.generateStylesJSON(host, protocol) Try / catch
try { return await mapService.generateStylesJSON(host) } catch (e) { if (e instanceof Error && e.message === 'Base map assets are missing from storage/maps') { return { statusCode: 503, body: 'Map assets not provisioned' } } throw e } Prevention
- Provision base assets at startup or via a setup command
- Mount a persistent volume for storage/maps
- Include asset presence in readiness probes
When it happens
Trigger: Hitting the styles endpoint before any base map provisioning has run — e.g. fresh install where ensureWorldBasemap/ensureBaseAssets was never invoked, or the storage directory was wiped.
Common situations: Fresh deployments where startup provisioning was skipped or failed; storage volume remounted empty; docker image built without baked-in assets; mapStoragePath misconfigured to a different directory than the one provisioned.
Related errors
- Base map assets are missing and could not be downloaded. Ple
- Base styles file not found in storage/maps
- Storage drive not available: cannot write to ${STORAGE_BASE}
- Invalid PMTiles file URL: ${url}. URL must end with .pmtiles
- Could not determine filename from URL
AI-assisted analysis of Crosstalk-Solutions/project-nomad@0bd1c6f4f9 (2026-08-27).
Data as JSON: /api/errors/aaea1c7a59070d3c.
Report an issue: GitHub.