koala73/worldmonitor · error · Error

Redis HTTP ${resp.status}

Error message

Redis HTTP ${resp.status}

What it means

Thrown by `rawRedisEval` in api/oauth/_refresh-recovery.ts:207 when the Upstash Redis REST API answers the EVAL POST with a non-2xx HTTP status. It signals a transport/auth-level failure rather than a script-level one (which comes back 200 with an `error` field). The fetch has a 3-second AbortSignal timeout, so timeouts surface as AbortError, not this message.

Source

Thrown at api/oauth/_refresh-recovery.ts:207

}

async function rawRedisEval(
  script: string,
  keys: string[],
  args: Array<string | number>,
): Promise<unknown> {
  const { url, token } = redisConfig();
  const resp = await fetch(`${url}/`, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${token}`,
      'Content-Type': 'application/json',
      'User-Agent': 'worldmonitor-edge/1.0',
    },
    body: JSON.stringify(['EVAL', script, String(keys.length), ...keys, ...args]),
    signal: AbortSignal.timeout(3_000),
  });
  if (!resp.ok) throw new Error(`Redis HTTP ${resp.status}`);
  const data = (await resp.json().catch(() => null)) as { result?: unknown; error?: string } | null;
  if (data?.error) throw new Error(`Redis EVAL failed: ${data.error}`);
  if (!data || !Object.prototype.hasOwnProperty.call(data, 'result')) {
    throw new Error('Redis EVAL returned an invalid response');
  }
  return data.result;
}

function parseStoredJson(value: unknown): unknown {
  if (typeof value !== 'string') throw new Error('Redis returned an invalid stored value');
  try {
    return JSON.parse(value);
  } catch {
    throw new Error('Redis returned malformed JSON');
  }
}

export async function rawRedisBeginRefreshAttempt(

View on GitHub (pinned to a96956387a)

Solutions

  1. Check the status: 401/403 means fix `UPSTASH_REDIS_REST_TOKEN`; 404 means fix `UPSTASH_REDIS_REST_URL`; 429 means rate limit — reduce call frequency or upgrade plan; 5xx is a transient Upstash issue — retry
  2. Verify the URL points to the correct live Upstash database and the token belongs to it
  3. Retry the OAuth refresh; the recovery flow is designed so a retryable failure does not lose the refresh token (restore/replay protection handles it)
Defensive patterns

Strategy: retry

Type guard

function isRedisHttpError(e: unknown): e is Error & { status?: number } {
  const m = /^Redis HTTP (\d+)$/.exec(e instanceof Error ? e.message : '');
  return m !== null;
}

Try / catch

try {
  await beginRefreshAttempt(token, id);
} catch (e) {
  if (isRedisHttpError(e)) {
    const status = Number(/\d+$/.exec(e.message)[0]);
    if (status === 429 || status >= 500) await retryWithBackoff(); // transient
    else reportConfigIssue(e); // 401/403/404 — fix credentials/URL
  } else throw e;
}

Prevention

When it happens

Trigger: An expired or wrong `UPSTASH_REDIS_REST_TOKEN` (401), a wrong `UPSTASH_REDIS_REST_URL` (404), rate limiting (429), or Upstash/platform 5xx outages during an OAuth refresh attempt EVAL call.

Common situations: Rotated Upstash credentials not updated in Vercel env; pointing the URL at a deleted database; hitting Upstash free-tier rate limits during refresh storms; transient Upstash incidents.

Related errors


AI-assisted analysis of koala73/worldmonitor@a96956387a (2026-08-27). Data as JSON: /api/errors/7b7ff6a6d7fb74d1. Report an issue: GitHub.