Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
364c2d9
feat: Add ignore-missing-files cli option to avoid crashing at startup
andrewlaguna824 Dec 17, 2025
d4eb752
update
andrewlaguna824 Dec 20, 2025
fbce4e4
Merge branch 'master' of github.com:maptiler/tileserver-gl into andre…
andrewlaguna824 Dec 20, 2025
f0ab1df
cleanup
andrewlaguna824 Dec 20, 2025
9110fea
package lock
andrewlaguna824 Dec 20, 2025
83ec5ff
cli description
andrewlaguna824 Dec 20, 2025
7333ff7
Only add styles to repository if all sources resolve
andrewlaguna824 Dec 21, 2025
f04b3ad
Remove existing style from repo if it has bad sources
andrewlaguna824 Dec 22, 2025
3fa5265
Revert "Remove existing style from repo if it has bad sources"
andrewlaguna824 Dec 22, 2025
bb3d6f2
clean up log message
andrewlaguna824 Dec 22, 2025
1719140
Do not add style to repo if it has missing source
andrewlaguna824 Dec 22, 2025
52cfe83
remove redundant checks from serve_rendered.js since we validate in s…
andrewlaguna824 Dec 22, 2025
3a338b7
cleanup
andrewlaguna824 Dec 22, 2025
fb5e974
cleanup
andrewlaguna824 Dec 23, 2025
c7f2e2a
feat: Add ignore-missing-files cli option to avoid crashing at startup
andrewlaguna824 Dec 17, 2025
72ef436
update
andrewlaguna824 Dec 20, 2025
58a45df
cleanup
andrewlaguna824 Dec 20, 2025
f6c6ec1
package lock
andrewlaguna824 Dec 20, 2025
3b0ebde
cli description
andrewlaguna824 Dec 20, 2025
f42bf64
Only add styles to repository if all sources resolve
andrewlaguna824 Dec 21, 2025
ae97247
Remove existing style from repo if it has bad sources
andrewlaguna824 Dec 22, 2025
6ef9b5b
Revert "Remove existing style from repo if it has bad sources"
andrewlaguna824 Dec 22, 2025
959537e
clean up log message
andrewlaguna824 Dec 22, 2025
48c3385
Do not add style to repo if it has missing source
andrewlaguna824 Dec 22, 2025
e29eaff
remove redundant checks from serve_rendered.js since we validate in s…
andrewlaguna824 Dec 22, 2025
863fbb2
cleanup
andrewlaguna824 Dec 22, 2025
332fc77
cleanup
andrewlaguna824 Dec 23, 2025
6c0e468
Merge branch 'andrewlaguna824/ignore-missing-files' of github.com:and…
andrewlaguna824 Jan 6, 2026
ce8226c
pr comment: handle unconfigured data source in the style
andrewlaguna824 Jan 6, 2026
52b9ee3
Merge branch 'master' into andrewlaguna824/ignore-missing-files
acalcutt Jan 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ program
'-f|--log_format <format>',
'define the log format: https://github.com/expressjs/morgan#morganformat-options',
)
.option(
'--ignore-missing-files',
'Continue startup even if configured mbtiles/pmtiles files are missing',
)
.version(packageJson.version, '-v, --version');
program.parse(process.argv);
const opts = program.opts();
Expand All @@ -132,6 +136,7 @@ const startServer = (configPath, config) => {
logFormat: opts.log_format,
fetchTimeout: opts.fetchTimeout,
publicUrl,
ignoreMissingFiles: opts.ignoreMissingFiles,
});
};

Expand Down
62 changes: 41 additions & 21 deletions src/serve_data.js
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ export const serve_data = {
* @returns {Promise<void>}
*/
add: async function (options, repo, params, id, programOpts) {
const { publicUrl, verbose } = programOpts;
const { publicUrl, verbose, ignoreMissingFiles } = programOpts;
let inputFile;
let inputType;
if (params.pmtiles) {
Expand Down Expand Up @@ -542,8 +542,18 @@ export const serve_data = {

// Only check file stats for local files, not remote URLs
if (!isValidRemoteUrl(inputFile)) {
const inputFileStats = await fsp.stat(inputFile);
if (!inputFileStats.isFile() || inputFileStats.size === 0) {
try {
const inputFileStats = await fsp.stat(inputFile);
if (!inputFileStats.isFile() || inputFileStats.size === 0) {
throw Error(`Not valid input file: "${inputFile}"`);
}
} catch (err) {
if (ignoreMissingFiles) {
console.log(
`WARN: Data source '${id}' file not found: "${inputFile}" - skipping`,
);
return;
}
throw Error(`Not valid input file: "${inputFile}"`);
}
}
Expand All @@ -555,24 +565,34 @@ export const serve_data = {
tileJSON['encoding'] = params['encoding'];
tileJSON['tileSize'] = params['tileSize'];

if (inputType === 'pmtiles') {
source = openPMtiles(
inputFile,
params.s3Profile,
params.requestPayer,
params.s3Region,
params.s3UrlFormat,
verbose,
);
sourceType = 'pmtiles';
const metadata = await getPMtilesInfo(source, inputFile);
Object.assign(tileJSON, metadata);
} else if (inputType === 'mbtiles') {
sourceType = 'mbtiles';
const mbw = await openMbTilesWrapper(inputFile);
const info = await mbw.getInfo();
source = mbw.getMbTiles();
Object.assign(tileJSON, info);
try {
if (inputType === 'pmtiles') {
source = openPMtiles(
inputFile,
params.s3Profile,
params.requestPayer,
params.s3Region,
params.s3UrlFormat,
verbose,
);
sourceType = 'pmtiles';
const metadata = await getPMtilesInfo(source, inputFile);
Object.assign(tileJSON, metadata);
} else if (inputType === 'mbtiles') {
sourceType = 'mbtiles';
const mbw = await openMbTilesWrapper(inputFile);
const info = await mbw.getInfo();
source = mbw.getMbTiles();
Object.assign(tileJSON, info);
}
} catch (err) {
if (ignoreMissingFiles) {
console.log(
`WARN: Unable to open data source '${id}' from "${inputFile}": ${err.message} - skipping (requests will return 404)`,
);
return;
}
throw err;
}

delete tileJSON['filesize'];
Expand Down
23 changes: 21 additions & 2 deletions src/serve_style.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ export const serve_style = {
reportTiles,
reportFont,
) {
const { publicUrl } = programOpts;
const { publicUrl, ignoreMissingFiles } = programOpts;
const styleFile = path.resolve(options.paths.styles, params.style);
const styleJSON = clone(style);

Expand Down Expand Up @@ -247,6 +247,9 @@ export const serve_style = {
return false;
}

// Track missing sources
const missingSources = [];

for (const name of Object.keys(styleJSON.sources)) {
// eslint-disable-next-line security/detect-object-injection -- name is from Object.keys of style sources
const source = styleJSON.sources[name];
Expand All @@ -270,7 +273,9 @@ export const serve_style = {

const identifier = reportTiles(dataId, protocol);
if (!identifier) {
return false;
// This datasource is missing or invalid in some way
missingSources.push(name);
continue;
}
source.url = `local://data/${identifier}.json`;
}
Expand All @@ -286,6 +291,20 @@ export const serve_style = {
}
}

// Check if any sources are missing after processing all of them
if (missingSources.length > 0) {
if (ignoreMissingFiles) {
console.log(
`WARN: Style '${id}' references ${missingSources.length} missing data source(s): [${missingSources.join(', ')}] - not adding style`,
);
} else {
console.log(
`ERROR: Style '${id}' references missing data source(s): [${missingSources.join(', ')}]`,
);
}
return false;
}

for (const obj of styleJSON.layers) {
if (obj['type'] === 'symbol') {
const fonts = (obj['layout'] || {})['text-font'];
Expand Down
46 changes: 45 additions & 1 deletion src/server.js
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested these changes and everything works as expected, but only if the data source is configured: If there is a unconfigured data source in the style, we will have the previous behaviour.

This fixed the issue for me: okimiko@cc9cff8

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Made the suggested changes and tested it on my end.

Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,36 @@ async function start(opts) {
}
}
if (dataItemId) {
// input files exists in the data config, return found id
// Data source exists in config, now validate file exists
// eslint-disable-next-line security/detect-object-injection -- dataItemId is validated above
const dataSource = data[dataItemId];
const fileType = dataSource.pmtiles ? 'pmtiles' : 'mbtiles';
const fileName = dataSource[fileType];

// Skip validation for remote URLs
if (fileName && !isValidRemoteUrl(fileName)) {
const filePath = path.resolve(options.paths[fileType], fileName);
try {
const stats = fs.statSync(filePath);
if (!stats.isFile() || stats.size === 0) {
if (opts.ignoreMissingFiles) {
// File doesn't exist or is empty - return undefined to skip
return undefined;
}
// File missing but flag not set - let it fail later
return dataItemId;
}
} catch (err) {
// File doesn't exist
if (opts.ignoreMissingFiles) {
return undefined;
}
// File missing but flag not set - let it fail later
return dataItemId;
}
}

// File exists or is remote URL, return the id
return dataItemId;
} else {
if (!allowMoreData) {
Expand All @@ -257,6 +286,21 @@ async function start(opts) {
if (isValidRemoteUrl(styleSourceId)) {
id =
fnv1a(styleSourceId) + '_' + id.replace(/^.*\/(.*)$/, '$1');
} else {
try {
const stats = fs.statSync(styleSourceId);
if (!stats.isFile() || stats.size === 0) {
if (opts.ignoreMissingFiles) {
// File doesn't exist or is empty - return undefined to skip
return undefined;
}
}
} catch (err) {
// File doesn't exist
if (opts.ignoreMissingFiles) {
return undefined;
}
}
}
// eslint-disable-next-line security/detect-object-injection -- id is being checked for existence before modification
while (data[id]) id += '_'; //if the data source id already exists, add a "_" untill it doesn't
Expand Down
Loading