Crosstalk-Solutions/project-nomad · error · Error
Could not determine filename from URL
Error message
Could not determine filename from URL
What it means
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.
Source
Thrown at admin/app/services/map_service.ts:271
logger.error(`[MapService] Failed to create InstalledResource for ${filename}:`, error)
}
}
}
async downloadRemote(url: string): Promise<{ filename: string; jobId?: string }> {
const parsed = new URL(url)
if (!parsed.pathname.endsWith('.pmtiles')) {
throw new Error(`Invalid PMTiles file URL: ${url}. URL must end with .pmtiles`)
}
const existing = await RunDownloadJob.getActiveByUrl(url)
if (existing) {
throw new Error(`Download already in progress for URL ${url}`)
}
const filename = url.split('/').pop()
if (!filename) {
throw new Error('Could not determine filename from URL')
}
const filepath = join(process.cwd(), this.mapStoragePath, 'pmtiles', filename)
// First, ensure base assets are present - regions depend on them
const baseAssetsExist = await this.ensureBaseAssets()
if (!baseAssetsExist) {
throw new Error(
'Base map assets are missing and could not be downloaded. Please check your connection and try again.'
)
}
// Parse resource metadata
const parsedFilename = CollectionManifestService.parseMapFilename(filename)
const resourceMetadata = parsedFilename
? { resource_id: parsedFilename.resource_id, version: parsedFilename.version, collection_ref: null }
: undefinedView on GitHub (pinned to 0bd1c6f4f9)
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
Example fix
// before
await mapService.downloadRemote('https://tiles.example.com/pmtiles/')
// after
await mapService.downloadRemote('https://tiles.example.com/pmtiles/region.pmtiles') Defensive patterns
Strategy: validation
Validate before calling
function getFilenameFromUrl(url: string): string | null {
try {
const seg = new URL(url).pathname.split('/').filter(Boolean).pop()
return seg && seg.endsWith('.pmtiles') ? seg : null
} catch { return null }
}
const filename = getFilenameFromUrl(url)
if (!filename) throw new Error('URL must point to a .pmtiles file')
await mapService.downloadRemote(url) Type guard
const isFileUrl = (u: string): boolean => {
try { return new URL(u).pathname.split('/').pop() !== '' } catch { return false }
} Try / catch
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 } Prevention
- 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)
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Invalid PMTiles file URL: ${url}. URL must end with .pmtiles
- Filename is required
- Invalid document slug
- Base map assets are missing and could not be downloaded. Ple
- Base map assets are missing from storage/maps
AI-assisted analysis of Crosstalk-Solutions/project-nomad@0bd1c6f4f9 (2026-08-27).
Data as JSON: /api/errors/959774cb0231b463.
Report an issue: GitHub.