{"record":{"id":"0d1dbaa002ce418b","repo":"Crosstalk-Solutions/project-nomad","slug":"base-styles-file-not-found-in-storage-maps","errorCode":null,"errorMessage":"Base styles file not found in storage/maps","messagePattern":"Base styles file not found in storage/maps","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"admin/app/services/map_service.ts","lineNumber":355,"sourceCode":"      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    */\n    const sources = this.generateSourcesArray(host, regions, protocol)\n    const baseUrl = this.getPublicFileBaseUrl(host, this.basemapsAssetsDir, protocol)\n\n    const styles = await this.generateStylesFile(\n      rawStyles,\n      sources,","sourceCodeStart":337,"sourceCodeEnd":373,"githubUrl":"https://github.com/Crosstalk-Solutions/project-nomad/blob/0bd1c6f4f9888d577fe232de06ac144bb8337131/admin/app/services/map_service.ts#L337-L373","documentation":"After confirming base assets exist, generateStylesJSON reads the base styles JSON file via getFile. If the read returns falsy (file deleted between the existence check and the read, empty file, or the existence check passing via cache while the file is actually gone), this error is thrown.","triggerScenarios":"Race condition where storage/maps assets are deleted or replaced while a styles request is in flight; an empty (0-byte) base styles file; a stale cache in checkBaseAssetsExist(useCache=true) hiding a missing file.","commonSituations":"Concurrent deployment pruning storage; partially-written file after an interrupted provisioning step; file permissions letting stat succeed but read fail/return empty.","solutions":["Check that the base styles file exists and is non-empty in storage/maps; restore or re-provision it","Re-run the full base asset provisioning step to rewrite the file atomically","If it recurs under load, call checkBaseAssetsExist(false) to bypass the cache before generating styles"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"const path = join(storageDir, 'styles.json')\nconst stat = await fs.promises.stat(path).catch(() => null)\nif (!stat || stat.size === 0) await mapService.ensureBaseAssets()","typeGuard":null,"tryCatchPattern":"try { return await mapService.generateStylesJSON(host) } catch (e) { if (e instanceof Error && e.message.includes('Base styles file not found')) { await mapService.ensureBaseAssets(); return mapService.generateStylesJSON(host) } throw e }","preventionTips":["Write provisioned files atomically (tmp + rename) so partial files never appear","Bypass the existence-check cache (pass useCache=false) after deployments","Alert on 0-byte files in storage/maps"],"tags":["storage","file-read","styles"],"backgroundTag":"missing-required-assets","analyzedSha":"0bd1c6f4f9888d577fe232de06ac144bb8337131","analyzedAt":"2026-08-27T05:34:15.424Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}