fix(overpass): read failure phrases from the remark, not element tags

overpassLooksRuntimeError and overpassLooksRateLimited searched the whole
200 body, element tags included. A result containing a place named
"Timed Out Escape Rooms" (or any tag with "runtime error", "out of
memory", "too many requests" or "rate_limited") was refused as an
upstream failure, and the endpoint was put on cooldown for every other
query.

Parse the body once. A data reply (one with an elements array) reports
failure in its remark, so the phrase checks run on the remark. Any other
body, an error page or JSON without elements, is matched whole as
before.
This commit is contained in:
Aditya committed 2026-10-16 16:52:01 +05:30
1 parent d4492d8f8c
commit a316e12323
4 files changed
+50 -5

No files matched your search

+18 -4
View File
@@ -14,7 +14,7 @@ import { simplifyOverpassPayloadBody } from './geometry.js';
* Checks for known rate-limit phrases in the body text regardless of
* HTTP status code, since some mirrors return 200 with an error payload.
*
* @param {string} bodyText - Upstream response body.
* @param {string} bodyText - The remark of a data reply, or a non-data body.
* @returns {boolean} True if the body looks rate-limited.
*/
function overpassLooksRateLimited(bodyText) {
@@ -41,6 +41,14 @@ function overpassLooksRuntimeError(bodyText) {
);
}
function parseJson(text) {
try {
return JSON.parse(text);
} catch {
return undefined;
}
}
/**
* True only for an upstream response that is actually Overpass data.
*
@@ -151,15 +159,22 @@ async function fetchOverpassPayload(
signal: controller.signal,
});
const responseBody = await readBody(upstream, maxResponseBytes);
const parsed = parseJson(responseBody);
// An Overpass data reply reports failure in its remark; its element
// tags are data and can contain any phrase. Any other body (an error
// page, or JSON without elements) is matched whole.
const failureText = Array.isArray(parsed?.elements)
? String(parsed.remark || '')
: responseBody;
const rateLimited =
upstream.status === 429 ||
upstream.status === 406 ||
overpassLooksRateLimited(responseBody);
overpassLooksRateLimited(failureText);
if (
rateLimited ||
upstream.status < 200 ||
upstream.status >= 300 ||
overpassLooksRuntimeError(responseBody)
overpassLooksRuntimeError(failureText)
) {
const failures = (previous?.failures || 0) + 1;
const delay = retryDelay(
@@ -178,7 +193,6 @@ async function fetchOverpassPayload(
failure = refusal(status, delay);
continue;
}
const parsed = JSON.parse(responseBody);
if (!Array.isArray(parsed?.elements) || parsed.remark)
throw new Error('Malformed Overpass response');
cooldowns.delete(endpoint);