koala73/worldmonitor · error

IMD_PROXY_URL_MISSING

Error message

IMD_PROXY_URL_MISSING

What it means

createImdProxyFetch(rawProxyUrl) builds a proxy-backed fetch for IMD data. Before constructing it, it normalizes the input with String(rawProxyUrl || '').trim() and throws IMD_PROXY_URL_MISSING when the result is empty. The proxy URL is required configuration — without it the factory cannot create a working fetcher, so it fails fast at setup time.

Solutions

  1. Set the proxy URL environment variable in the deployment environment (e.g. IMD_PROXY_URL) and pass it: createImdProxyFetch(process.env.IMD_PROXY_URL).
  2. Check for typos in the env var name and verify the value is non-empty after trim.
  3. If the proxy is optional, branch before calling the factory: only create the proxy fetch when a URL is present.

Example fix

// before
const imdFetch = createImdProxyFetch(process.env.IMD_PROXY_URL); // unset
// after
if (!process.env.IMD_PROXY_URL) throw new Error('Set IMD_PROXY_URL before enabling the IMD proxy');
const imdFetch = createImdProxyFetch(process.env.IMD_PROXY_URL);
Defensive patterns

Strategy: validation

Validate before calling

const proxyUrl = (process.env.IMD_PROXY_URL ?? '').trim();
if (!proxyUrl) {
  throw new Error('IMD_PROXY_URL is required when the IMD proxy path is enabled; set it in the environment');
}
const imdFetch = createImdProxyFetch(proxyUrl);

Type guard

function hasProxyUrl(v) {
  return typeof v === 'string' && v.trim().length > 0;
}

Try / catch

let imdFetch;
try {
  imdFetch = createImdProxyFetch(process.env.IMD_PROXY_URL);
} catch (err) {
  if (err.message === 'IMD_PROXY_URL_MISSING') {
    console.error('IMD_PROXY_URL is not configured; falling back to direct fetch or disabling IMD ingest');
    imdFetch = null;
  } else throw err;
}

Prevention

When it happens

Trigger: Calling createImdProxyFetch(undefined), createImdProxyFetch(''), createImdProxyFetch(' '), or createImdProxyFetch(null) — typically because the environment variable holding the proxy URL (e.g. process.env.IMD_PROXY_URL) is unset or whitespace-only.

Common situations: Deploying to an environment where the proxy secret/variable was never configured; passing an empty string after trimming a config file value; a worker reading the wrong env var name; forgetting the argument when wiring the proxy fetch in bootstrap code.

Understand the failure class

Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of koala73/worldmonitor@7d06c8633d (2026-09-15). Data as JSON: /api/errors/569ecd0d43b74d85. Report an issue: GitHub.

Appendix: source

Thrown at scripts/lib/imd-cyclone-marine.mjs:774

  const headers = { Accept: 'application/json', 'User-Agent': userAgent };
  if (apiKey) headers[apiKeyHeader] = apiKey;
  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;

View on GitHub (pinned to 7d06c8633d)