koala73/worldmonitor · error · Error

Redis EVAL failed: ${data.error}

Error message

Redis EVAL failed: ${data.error}

What it means

Thrown by `rawRedisEval` in api/oauth/_refresh-recovery.ts:209 when Upstash returns HTTP 200 but the JSON body contains an `error` field, meaning the EVAL command itself failed server-side. Typical Lua failures include script compile errors, WRONGTYPE operations against mis-typed keys, or argument-shape problems — the Upstash error string is embedded in the message.

Source

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

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(
  refreshToken: string,
  attemptId: string,

View on GitHub (pinned to a96956387a)

Solutions

  1. Read the embedded Upstash error string — it names the exact Lua/Redis failure (e.g. WRONGTYPE, script error)
  2. Inspect the offending keys (`oauth:refresh:<token>`, `oauth:refresh:family:attempt:*`) with `GET`/`TYPE` and delete or rewrite stale/mistyped values
  3. If caused by a deployment format change, flush/expire old-format keys and let the next refresh repopulate them
Defensive patterns

Strategy: try-catch

Type guard

function isRedisEvalError(e: unknown): boolean {
  return e instanceof Error && e.message.startsWith('Redis EVAL failed:');
}

Try / catch

try {
  await beginRefreshAttempt(token, id);
} catch (e) {
  if (isRedisEvalError(e)) {
    // log e.message (contains the Upshade/Lua error), inspect key types; non-retryable until data is fixed
    await alertOps(e);
  } else throw e;
}

Prevention

When it happens

Trigger: The Lua refresh-attempt script hitting a WRONGTYPE because `oauth:refresh:<token>` or a family key holds a non-string Redis type; a script change deployed with mismatched KEYS/ARGV; Upstash rejecting EVAL on a read-only replica.

Common situations: Keys written by a different tool/seed script with a non-string type (hash/set) colliding with `oauth:refresh:*`; version skew between deployed Edge code and an older/newer key format; manual Redis edits via console.

Related errors


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