koala73/worldmonitor · error
IMD_PROXY_URL_INVALID
Error message
IMD_PROXY_URL_INVALID
What it means
After a non-empty proxy URL is provided, createImdProxyFetch() parses it with parseProxyConfig() and requires the resulting config to exist with tls === true (an HTTPS proxy endpoint). If parsing fails or the proxy is not TLS, it throws IMD_PROXY_URL_INVALID. This guarantees the proxy connection is encrypted before any IMD traffic is sent through it.
Solutions
- Use an https:// proxy URL so parseProxyConfig yields tls === true (e.g. https://proxy.example.com:8443).
- Log/inspect the raw env value to confirm it is a complete, well-formed URL with a supported scheme.
- If only a plaintext HTTP proxy exists, front it with a TLS-terminating wrapper or use a different egress proxy; do not attempt to bypass the TLS requirement.
- Check that no whitespace/quotes from the secret store leaked into the value.
Example fix
// before
createImdProxyFetch('http://proxy.internal:8080');
// after
createImdProxyFetch('https://proxy.internal:8443'); Defensive patterns
Strategy: validation
Validate before calling
const proxyUrl = (process.env.IMD_PROXY_URL ?? '').trim();
let parsed;
try { parsed = new URL(proxyUrl); } catch { parsed = null; }
if (!parsed || parsed.protocol !== 'https:') {
throw new Error(`IMD_PROXY_URL must be a well-formed https:// URL, got: ${proxyUrl}`);
}
const imdFetch = createImdProxyFetch(proxyUrl); Type guard
function isHttpsProxyUrl(v) {
if (typeof v !== 'string') return false;
try {
const u = new URL(v.trim());
return u.protocol === 'https:' && Boolean(u.hostname);
} catch {
return false;
}
} Try / catch
try {
imdFetch = createImdProxyFetch(proxyUrl);
} catch (err) {
if (err.message === 'IMD_PROXY_URL_INVALID') {
console.error(`IMD_PROXY_URL is not a valid TLS proxy endpoint: ${proxyUrl}`);
throw new Error('Fix IMD_PROXY_URL to an https:// proxy endpoint before starting');
}
throw err;
} Prevention
- Store the proxy URL with the https:// scheme included in the secret store, not just host:port.
- Validate the scheme at config-load time with a URL parse before the app starts.
- Never configure plaintext http:// or SOCKS proxies for this path; the library requires TLS by design.
- Watch for copied values with surrounding quotes/whitespace that break URL parsing.
When it happens
Trigger: Passing a malformed URL (e.g. 'not-a-url'), a proxy URL using a scheme parseProxyConfig rejects, or an http:// (non-TLS) proxy URL such as 'http://proxy.internal:8080' — parseProxyConfig returns null/undefined or a config whose tls !== true.
Common situations: Configuring an internal plaintext HTTP proxy out of habit; pasting a SOCKS or socks5:// URL the parser does not support; a truncated/garbled value in the secret store; migrating config between environments where the scheme changed.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- IMD_PROXY_URL_MISSING
- Acquisition provider '${name}' is not configured. Set the re
- EXA_API_KEY is required for exa-search adapter
- Generic adapter requires acquisition config (retailer: ${ctx
- HTTP ${resp.status}
AI-assisted analysis of koala73/worldmonitor@7d06c8633d (2026-09-15).
Data as JSON: /api/errors/c065b7deaa21fd05.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/imd-cyclone-marine.mjs:776
if (apiToken) headers.Authorization = `Bearer ${apiToken}`;
const response = await fetchFn(url, {
headers,
redirect: 'error',
signal: AbortSignal.timeout(timeoutMs),
});
if (!response.ok) {
const err = new Error(`HTTP ${response.status}`);
err.httpStatus = response.status;
throw err;
}
return readBoundedJsonResponse(response, maxBytes);
}
export function createImdProxyFetch(rawProxyUrl, { proxyFetchFn = proxyFetch } = {}) {
const proxyUrl = String(rawProxyUrl || '').trim();
if (!proxyUrl) throw new Error('IMD_PROXY_URL_MISSING');
const proxyConfig = parseProxyConfig(proxyUrl);
if (!proxyConfig || proxyConfig.tls !== true) throw new Error('IMD_PROXY_URL_INVALID');
return async (url, init = {}) => {
if (!isAllowedImdHost(url)) throw new Error('UNTRUSTED_SOURCE_HOST');
const headers = init.headers || {};
const response = await proxyFetchFn(url, proxyConfig, {
accept: headers.Accept || headers.accept || '*/*',
headers,
method: init.method || 'GET',
body: init.body ?? null,
maxResponseBytes: IMD_MAX_BYTES,
timeoutMs: IMD_TIMEOUT_MS,
signal: init.signal,
});
const responseHeaders = {};
if (response.contentType) responseHeaders['Content-Type'] = response.contentType;
if (response.location) responseHeaders.Location = response.location;
const status = Number(response.status) || 502;
const body = status === 204 || status === 205 || status === 304
? nullView on GitHub (pinned to 7d06c8633d)