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

  1. Run the base asset provisioning (ensureBaseAssets/ensureWorldBasemap, or your app's setup command) so storage/maps is populated
  2. Verify mapStoragePath config points to the directory containing the base assets
  3. 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

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


AI-assisted analysis of Crosstalk-Solutions/project-nomad@0bd1c6f4f9 (2026-08-27). Data as JSON: /api/errors/aaea1c7a59070d3c. Report an issue: GitHub.