{"record":{"id":"569ecd0d43b74d85","repo":"koala73/worldmonitor","slug":"imd-proxy-url-missing","errorCode":null,"errorMessage":"IMD_PROXY_URL_MISSING","messagePattern":"IMD_PROXY_URL_MISSING","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/lib/imd-cyclone-marine.mjs","lineNumber":774,"sourceCode":"  const headers = { Accept: 'application/json', 'User-Agent': userAgent };\n  if (apiKey) headers[apiKeyHeader] = apiKey;\n  if (apiToken) headers.Authorization = `Bearer ${apiToken}`;\n  const response = await fetchFn(url, {\n    headers,\n    redirect: 'error',\n    signal: AbortSignal.timeout(timeoutMs),\n  });\n  if (!response.ok) {\n    const err = new Error(`HTTP ${response.status}`);\n    err.httpStatus = response.status;\n    throw err;\n  }\n  return readBoundedJsonResponse(response, maxBytes);\n}\n\nexport function createImdProxyFetch(rawProxyUrl, { proxyFetchFn = proxyFetch } = {}) {\n  const proxyUrl = String(rawProxyUrl || '').trim();\n  if (!proxyUrl) throw new Error('IMD_PROXY_URL_MISSING');\n  const proxyConfig = parseProxyConfig(proxyUrl);\n  if (!proxyConfig || proxyConfig.tls !== true) throw new Error('IMD_PROXY_URL_INVALID');\n  return async (url, init = {}) => {\n    if (!isAllowedImdHost(url)) throw new Error('UNTRUSTED_SOURCE_HOST');\n    const headers = init.headers || {};\n    const response = await proxyFetchFn(url, proxyConfig, {\n      accept: headers.Accept || headers.accept || '*/*',\n      headers,\n      method: init.method || 'GET',\n      body: init.body ?? null,\n      maxResponseBytes: IMD_MAX_BYTES,\n      timeoutMs: IMD_TIMEOUT_MS,\n      signal: init.signal,\n    });\n    const responseHeaders = {};\n    if (response.contentType) responseHeaders['Content-Type'] = response.contentType;\n    if (response.location) responseHeaders.Location = response.location;\n    const status = Number(response.status) || 502;","sourceCodeStart":756,"sourceCodeEnd":792,"githubUrl":"https://github.com/koala73/worldmonitor/blob/7d06c8633d256c18e38133030bc3613976a96ec9/scripts/lib/imd-cyclone-marine.mjs#L756-L792","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Set the proxy URL environment variable in the deployment environment (e.g. IMD_PROXY_URL) and pass it: createImdProxyFetch(process.env.IMD_PROXY_URL).","Check for typos in the env var name and verify the value is non-empty after trim.","If the proxy is optional, branch before calling the factory: only create the proxy fetch when a URL is present."],"exampleFix":"// before\nconst imdFetch = createImdProxyFetch(process.env.IMD_PROXY_URL); // unset\n// after\nif (!process.env.IMD_PROXY_URL) throw new Error('Set IMD_PROXY_URL before enabling the IMD proxy');\nconst imdFetch = createImdProxyFetch(process.env.IMD_PROXY_URL);","handlingStrategy":"validation","validationCode":"const proxyUrl = (process.env.IMD_PROXY_URL ?? '').trim();\nif (!proxyUrl) {\n  throw new Error('IMD_PROXY_URL is required when the IMD proxy path is enabled; set it in the environment');\n}\nconst imdFetch = createImdProxyFetch(proxyUrl);","typeGuard":"function hasProxyUrl(v) {\n  return typeof v === 'string' && v.trim().length > 0;\n}","tryCatchPattern":"let imdFetch;\ntry {\n  imdFetch = createImdProxyFetch(process.env.IMD_PROXY_URL);\n} catch (err) {\n  if (err.message === 'IMD_PROXY_URL_MISSING') {\n    console.error('IMD_PROXY_URL is not configured; falling back to direct fetch or disabling IMD ingest');\n    imdFetch = null;\n  } else throw err;\n}","preventionTips":["Add a startup assertion that IMD_PROXY_URL is set whenever the proxy code path is enabled.","Trim env values once at config-load time and reject empties early.","Document the required variable in deployment/onboarding docs and seed it in CI.","Distinguish 'proxy optional' from 'proxy required' in code so missing config degrades explicitly instead of throwing."],"tags":["configuration","proxy","missing-env-var","imd"],"backgroundTag":"missing-env-var","analyzedSha":"7d06c8633d256c18e38133030bc3613976a96ec9","analyzedAt":"2026-09-15T16:44:39.439Z","contentChangedAt":"2026-09-15T16:44:39.439Z","schemaVersion":2},"datasetVersion":"2026-09-15T18:17:12.389Z"}