koala73/worldmonitor · error · Error

Redis EVAL returned an invalid response

Error message

Redis EVAL returned an invalid response

What it means

Thrown by `rawRedisEval` in api/oauth/_refresh-recovery.ts:211 when the Redis REST response is HTTP 200 with no `error`, but the parsed body is null or lacks a `result` property. This is a protocol-shape guard: Upstash always wraps command output in `{ "result": ... }`, so a body without it means an unexpected gateway response, a non-JSON body that `resp.json()` failed to parse (caught → null), or an API version/endpoint mismatch.

Source

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

  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(
  refreshToken: string,
  attemptId: string,
): Promise<RefreshConsumeResult> {
  const refreshKey = `oauth:refresh:${refreshToken}`;

View on GitHub (pinned to a96956387a)

Solutions

  1. Confirm `UPSTASH_REDIS_REST_URL` is a genuine Upstash REST endpoint (ends with `.upstash.io`, no path suffix beyond what the client appends)
  2. Log/replicate the exact POST body (`['EVAL', ...]`) with curl against the configured URL to see the raw response shape
  3. If transient, retry — the recovery flow treats this as a retryable failure and preserves the refresh token
Defensive patterns

Strategy: retry

Type guard

function isInvalidRedisResponse(e: unknown): boolean {
  return e instanceof Error && e.message === 'Redis EVAL returned an invalid response';
}

Try / catch

try {
  await beginRefreshAttempt(token, id);
} catch (e) {
  if (isInvalidRedisResponse(e)) {
    await retryWithBackoff(); // usually transient gateway/shape issue; retryable-safe by design
  } else throw e;
}

Prevention

When it happens

Trigger: Upstash returning an HTML error/blank page with 200 (proxy or gateway quirk); `resp.json()` throwing and yielding null; a URL pointing at a non-Upstash endpoint that answers 200 with a different JSON shape.

Common situations: `UPSTASH_REDIS_REST_URL` pointing at a proxy or wrong service that returns 200 with different JSON; transient gateway oddities; Upstash API behavior changes.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


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