koala73/worldmonitor · error
MND_PROXY_RESPONSE_INVALID
MND_PROXY_RESPONSE_INVALID
Error message
MND_PROXY_RESPONSE_INVALID
What it means
fetchMndViaProxy routes Taiwan MND fetches through a configured proxy function (proxyRequestFn). After the proxy returns, the code validates the envelope: result.status must be an integer HTTP status in 200–599. A missing result, a non-integer status, or a status outside that range means the proxy returned a structurally invalid response, so MND_PROXY_RESPONSE_INVALID is thrown instead of building a Response object.
Solutions
- Log the raw proxyRequestFn result to see what shape was actually returned and compare it to the expected {status, buffer} envelope.
- Fix the proxy implementation/config so it maps transport failures to a valid HTTP status (200–599) and returns {status, buffer}; a socket failure should surface as its own error, not status 0.
- If the proxy library changed its return shape, adapt at the call site (e.g. read result.response.status) or pin/upgrade to a compatible version.
- Verify the correct proxyRequestFn is wired for the MND source (not a stub or another source's fetcher).
Example fix
// before: proxy returns transport-level result with no HTTP status
const result = await proxyRequestFn(url, proxyConfig, opts); // { ok: false, err: 'ECONNRESET' }
// after: normalize proxy failures into a valid status envelope before returning
const result = await proxyRequestFn(url, proxyConfig, opts);
if (!result || typeof result.status !== 'number') {
throw new Error(`PROXY_TRANSPORT_FAILURE:${result?.err ?? 'unknown'}`); // or map to status 502
} Defensive patterns
Strategy: validation
Validate before calling
// Validate the proxy envelope before handing it to fetchMndViaProxy
function isValidProxyStatus(result) {
return Number.isInteger(result?.status) && result.status >= 200 && result.status <= 599;
} Type guard
function isMndProxyResult(result) {
return result != null
&& Number.isInteger(result.status)
&& result.status >= 200 && result.status <= 599
&& (result.status >= 300 || Buffer.isBuffer(result.buffer));
} Try / catch
try {
const response = await fetchMndViaProxy(input, init, proxyConfig, proxyRequestFn);
return response;
} catch (error) {
if (error?.message === 'MND_PROXY_RESPONSE_INVALID') {
logger.error({ proxyUrl: proxyConfig.url }, 'proxy returned invalid status envelope');
throw new SourceUnavailableError('MND proxy misbehaving');
}
throw error;
} Prevention
- Pin and integration-test your proxyRequestFn so its return contract ({status: 200–599, buffer}) is asserted.
- Have the proxy map transport failures to valid HTTP statuses (e.g. 502/504) instead of 0 or undefined.
- Type-check the proxy result at the proxy boundary, not just at the consumer.
- Add a canary test that exercises the real proxy path against a fixture server.
When it happens
Trigger: proxyRequestFn resolves with null/undefined, an object without a status field, a status like 0, NaN, a string, or a value <200 or >599 (e.g. a custom proxy error code such as 0 or 999) when fetching the Taiwan MND source.
Common situations: Proxy service crashes or returns its own error JSON instead of {status, buffer}; wrong proxyRequestFn injected in tests or DI; proxy library version change altered its return shape (e.g. status moved to result.response.status); network layer returns a 0 status on socket failure.
Related errors
- HTTP ${resp.status}
- HTTP ${resp.status}
- MCP server request failed
- serverUrl DNS resolution failed
- RESPONSE_TOO_LARGE
AI-assisted analysis of koala73/worldmonitor@7d06c8633d (2026-09-15).
Data as JSON: /api/errors/c27309e5c763904c.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/cross-strait-activity/adapters.mjs:1728
if (diagnostic) diagnostic.stage = 'parse';
return { text, status: response.status };
}
async function fetchBoundedText(fetchFn, url, sourceContract, diagnostic = null) {
const { text } = await fetchBoundedTextWithStatus(fetchFn, url, sourceContract, diagnostic);
return text;
}
async function fetchMndViaProxy(input, init, proxyConfig, proxyRequestFn) {
const maxResponseBytes = CROSS_STRAIT_SOURCE_CONTRACTS.taiwanMnd.maxResponseBytes;
const result = await proxyRequestFn(String(input), proxyConfig, {
headers: init.headers,
maxResponseBytes,
timeoutMs: REQUEST_TIMEOUT_MS,
signal: init.signal,
});
if (!Number.isInteger(result?.status) || result.status < 200 || result.status > 599) {
throw new Error('MND_PROXY_RESPONSE_INVALID');
}
if (result.status >= 300) {
return new Response(null, { status: result.status });
}
if (!Buffer.isBuffer(result.buffer)) throw new Error('MND_PROXY_RESPONSE_INVALID');
if (result.buffer.byteLength > maxResponseBytes) throw new Error('RESPONSE_TOO_LARGE');
return new Response(result.status === 204 || result.status === 205 ? null : result.buffer, {
status: result.status,
});
}
function shouldProxyJapanModFailure(error) {
const code = errorCode(error);
if (code === 'SOURCE_ERROR' || code === 'TIMEOUT' || code === 'JMOD_INDEX_EMPTY') return true;
const status = Number(/^HTTP_(\d{3})$/u.exec(code)?.[1]);
return status === 403
|| status === 408
|| status === 425View on GitHub (pinned to 7d06c8633d)