{"record":{"id":"959774cb0231b463","repo":"Crosstalk-Solutions/project-nomad","slug":"could-not-determine-filename-from-url","errorCode":null,"errorMessage":"Could not determine filename from URL","messagePattern":"Could not determine filename from URL","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"admin/app/services/map_service.ts","lineNumber":271,"sourceCode":"        logger.error(`[MapService] Failed to create InstalledResource for ${filename}:`, error)\n      }\n    }\n  }\n\n  async downloadRemote(url: string): Promise<{ filename: string; jobId?: string }> {\n    const parsed = new URL(url)\n    if (!parsed.pathname.endsWith('.pmtiles')) {\n      throw new Error(`Invalid PMTiles file URL: ${url}. URL must end with .pmtiles`)\n    }\n\n    const existing = await RunDownloadJob.getActiveByUrl(url)\n    if (existing) {\n      throw new Error(`Download already in progress for URL ${url}`)\n    }\n\n    const filename = url.split('/').pop()\n    if (!filename) {\n      throw new Error('Could not determine filename from URL')\n    }\n\n    const filepath = join(process.cwd(), this.mapStoragePath, 'pmtiles', filename)\n\n\n    // First, ensure base assets are present - regions depend on them\n    const baseAssetsExist = await this.ensureBaseAssets()\n    if (!baseAssetsExist) {\n      throw new Error(\n        'Base map assets are missing and could not be downloaded. Please check your connection and try again.'\n      )\n    }\n\n    // Parse resource metadata\n    const parsedFilename = CollectionManifestService.parseMapFilename(filename)\n    const resourceMetadata = parsedFilename\n      ? { resource_id: parsedFilename.resource_id, version: parsedFilename.version, collection_ref: null }\n      : undefined","sourceCodeStart":253,"sourceCodeEnd":289,"githubUrl":"https://github.com/Crosstalk-Solutions/project-nomad/blob/0bd1c6f4f9888d577fe232de06ac144bb8337131/admin/app/services/map_service.ts#L253-L289","documentation":"Thrown by MapService.downloadRemote when the last path segment of the provided URL cannot be used as a filename. Because url.split('/').pop() only returns empty for URLs ending in '/' (or being just '/'), this fires when the URL has no filename component and the service has nothing to name the downloaded PMTiles file.","triggerScenarios":"Calling downloadRemote with a URL like 'https://example.com/pmtiles/' (trailing slash, no filename) or 'https://example.com/' — any URL whose last segment after the final '/' is an empty string.","commonSituations":"Building the URL from user input or a directory listing without trimming/validating; concatenating a base URL with a missing filename variable; copy-pasting a directory URL instead of a file URL.","solutions":["Ensure the URL points to an actual .pmtiles file, not a directory (remove trailing slash or append the filename)","Validate the URL's last segment before calling downloadRemote (e.g. new URL(url).pathname.split('/').pop() is non-empty and ends with .pmtiles)","If the URL comes from UI input, add client-side validation with a clear message"],"exampleFix":"// before\nawait mapService.downloadRemote('https://tiles.example.com/pmtiles/')\n\n// after\nawait mapService.downloadRemote('https://tiles.example.com/pmtiles/region.pmtiles')","handlingStrategy":"validation","validationCode":"function getFilenameFromUrl(url: string): string | null {\n  try {\n    const seg = new URL(url).pathname.split('/').filter(Boolean).pop()\n    return seg && seg.endsWith('.pmtiles') ? seg : null\n  } catch { return null }\n}\nconst filename = getFilenameFromUrl(url)\nif (!filename) throw new Error('URL must point to a .pmtiles file')\nawait mapService.downloadRemote(url)","typeGuard":"const isFileUrl = (u: string): boolean => {\n  try { return new URL(u).pathname.split('/').pop() !== '' } catch { return false }\n}","tryCatchPattern":"try { await mapService.downloadRemote(url) } catch (e) { if (e instanceof Error && e.message.includes('Could not determine filename')) { /* fix URL, re-prompt user */ } else throw e }","preventionTips":["Trim trailing slashes from user-supplied URLs before use","Always test URLs with new URL(...) before passing to download APIs","Pair filename extraction with an extension check (.pmtiles)"],"tags":["url-parsing","validation","pmtiles"],"backgroundTag":"invalid-url-format","analyzedSha":"0bd1c6f4f9888d577fe232de06ac144bb8337131","analyzedAt":"2026-08-27T05:34:15.424Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}