{"record":{"id":"aaea1c7a59070d3c","repo":"Crosstalk-Solutions/project-nomad","slug":"base-map-assets-are-missing-from-storage-maps","errorCode":null,"errorMessage":"Base map assets are missing from storage/maps","messagePattern":"Base map assets are missing from storage/maps","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"admin/app/services/map_service.ts","lineNumber":349,"sourceCode":"      const response = await axios.head(url)\n\n      if (response.status !== 200) {\n        throw new Error(`Failed to fetch file info: ${response.status} ${response.statusText}`)\n      }\n\n      const contentLength = response.headers['content-length']\n      const size = contentLength ? parseInt(contentLength.toString(), 10) : 0\n\n      return { filename, size }\n    } catch (error: any) {\n      logger.error({ err: error }, '[MapService] Preflight check failed for URL')\n      return { message: 'Preflight check failed. Please verify the URL is valid and accessible.' }\n    }\n  }\n\n  async generateStylesJSON(host: string | null = null, protocol: string = 'http'): Promise<BaseStylesFile> {\n    if (!(await this.checkBaseAssetsExist())) {\n      throw new Error('Base map assets are missing from storage/maps')\n    }\n\n    const baseStylePath = join(this.baseDirPath, this.baseStylesFile)\n    const baseStyle = await getFile(baseStylePath, 'string')\n    if (!baseStyle) {\n      throw new Error('Base styles file not found in storage/maps')\n    }\n\n    const rawStyles = JSON.parse(baseStyle.toString()) as BaseStylesFile\n\n    const regions = (await this.listRegions()).files\n\n    /** If we have the host, use it to build public URLs, otherwise we'll fallback to defaults\n    * This is mainly useful because we need to know what host the user is accessing from in order to\n    * properly generate URLs in the styles file\n    * e.g. user is accessing from \"example.com\", but we would by default generate \"localhost:8080/...\" so maps would\n    * fail to load.\n    */","sourceCodeStart":331,"sourceCodeEnd":367,"githubUrl":"https://github.com/Crosstalk-Solutions/project-nomad/blob/0bd1c6f4f9888d577fe232de06ac144bb8337131/admin/app/services/map_service.ts#L331-L367","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nconst styles = await mapService.generateStylesJSON(host)\n\n// after\nawait mapService.ensureBaseAssets() // provision once at startup\nconst styles = await mapService.generateStylesJSON(host)","handlingStrategy":"fallback","validationCode":"if (!(await mapService.checkBaseAssetsExist(false))) { await mapService.ensureBaseAssets() }\nconst styles = await mapService.generateStylesJSON(host, protocol)","typeGuard":null,"tryCatchPattern":"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 }","preventionTips":["Provision base assets at startup or via a setup command","Mount a persistent volume for storage/maps","Include asset presence in readiness probes"],"tags":["storage","assets","styles","pmtiles"],"backgroundTag":"missing-required-assets","analyzedSha":"0bd1c6f4f9888d577fe232de06ac144bb8337131","analyzedAt":"2026-08-27T05:34:15.424Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}