koala73/worldmonitor · error

IMD_AUTH_HTTP_${response.status}

Error message

IMD_AUTH_HTTP_${response.status}

What it means

Thrown by mintImdApiToken in scripts/lib/imd-cyclone-marine.mjs when the POST to the IMD OAuth token endpoint returns a non-2xx HTTP status. The library converts the status code into a stable error string (IMD_AUTH_HTTP_<status>) which imdAuthFailureReason later maps to the failure reason surfaced to callers as { token: null, error }. It signals the upstream authentication API rejected the credential request before any token could be minted.

Solutions

  1. Verify the IMD email/password credentials are current and correctly loaded from env, then retry with valid credentials.
  2. Log response.status (it is embedded in the thrown message) and if 429 back off and retry later with jitter.
  3. Check whether IMD's token URL changed; a 301/302/404 means update IMD_OAUTH_TOKEN_URL.
  4. If 5xx, wait and retry — the failure reason propagates as IMD_AUTH_HTTP_5xx and the worker should retry on the next cycle.
  5. Confirm the outbound network/proxy can reach the IMD host (a proxy failure surfaces as a different IMD_PROXY_CONNECT_HTTP_* reason).

Example fix

// before
const response = await fetchFn(IMD_OAUTH_TOKEN_URL, { method: 'POST', body: JSON.stringify({ email: process.env.IMD_EMAIL, password: process.env.IMD_PASSWORD }) });
// after
// validate credentials are present before the request; handle specific statuses
if (!process.env.IMD_EMAIL || !process.env.IMD_PASSWORD) throw new Error('IMD credentials missing from env');
const response = await fetchFn(IMD_OAUTH_TOKEN_URL, { method: 'POST', body: JSON.stringify({ email: process.env.IMD_EMAIL, password: process.env.IMD_PASSWORD }) });
if (response.status === 429) await sleep(backoffMs); // then retry
Defensive patterns

Strategy: try-catch

Validate before calling

if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email) || !password) throw new Error('IMD credentials missing or malformed before auth request');

Type guard

function hasImdCredentials(env) { return typeof env.IMD_EMAIL === 'string' && env.IMD_EMAIL.includes('@') && typeof env.IMD_PASSWORD === 'string' && env.IMD_PASSWORD.length > 0; }

Try / catch

const { token, error } = await mintImdApiToken({ email, password });
if (!token) {
  if (/^IMD_AUTH_HTTP_429$/.test(error)) await sleep(backoffWithJitter());
  else if (/^IMD_AUTH_HTTP_5/.test(error)) scheduleRetryNextCycle();
  else throw new Error(`IMD auth rejected: ${error}`);
}

Prevention

When it happens

Trigger: POST { email, password } to IMD_OAUTH_TOKEN_URL responds with a non-ok status (e.g. 401 for wrong email/password, 403 for blocked IP, 429 for rate limiting, 5xx for IMD outage). redirect: 'error' also makes any redirect surface here as IMD_AUTH_HTTP_3xx.

Common situations: Expired or rotated IMD portal credentials in env config; IMD temporarily blocking datacenter IPs or rate-limiting token mints; IMD moving the OAuth endpoint so requests hit a redirect or 404; IMD-side outage returning 5xx.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


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

Appendix: source

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

  password,
  fetchFn = globalThis.fetch,
  userAgent = CHROME_UA,
  maxBytes = IMD_MAX_BYTES,
  timeoutMs = IMD_TIMEOUT_MS,
}) {
  try {
    const response = await fetchFn(IMD_OAUTH_TOKEN_URL, {
      method: 'POST',
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
        'User-Agent': userAgent,
      },
      body: JSON.stringify({ email, password }),
      redirect: 'error',
      signal: AbortSignal.timeout(timeoutMs),
    });
    if (!response.ok) throw new Error(`IMD_AUTH_HTTP_${response.status}`);
    let payload;
    try {
      payload = await readBoundedJsonResponse(response, maxBytes);
    } catch (err) {
      if (/^IMD_RESPONSE_TOO_LARGE:\d+$/.test(String(err?.message || ''))) throw err;
      throw new Error('IMD_AUTH_RESPONSE_INVALID');
    }
    const accessToken = typeof payload?.access_token === 'string' ? payload.access_token : '';
    const tokenType = typeof payload?.token_type === 'string' ? payload.token_type.trim() : '';
    const expiresIn = Number(payload?.expires_in);
    if (
      !/^[\u0021-\u007E]+$/.test(accessToken)
      || tokenType.toLowerCase() !== 'bearer'
      || !Number.isFinite(expiresIn)
      || expiresIn <= 0
    ) {
      throw new Error('IMD_AUTH_RESPONSE_INVALID');
    }

View on GitHub (pinned to 7d06c8633d)