koala73/worldmonitor · error · Error
Redis returned an invalid stored value
Error message
Redis returned an invalid stored value
What it means
Thrown by `parseStoredJson` in api/oauth/_refresh-recovery.ts:217 during `rawRedisBeginRefreshAttempt` when the Lua script consumed the refresh token but the stored value under `oauth:refresh:<token>` (returned as `result[1]`) is not a string. The script only returns stored strings from GET, so a non-string means an unexpected RESP type — e.g. false/null leaked through or a key holding a non-string type.
Source
Thrown at api/oauth/_refresh-recovery.ts:217
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}`;
const attemptKey = refreshFamilyAttemptKey(refreshToken);
const pointerKey = refreshFamilyPointerKey(refreshToken);
const attemptValue = JSON.stringify({ attempt_id: attemptId });
const attemptMarker = serializeRefreshAttemptMarker(attemptValue);
const script = [
"local value = redis.call('GET', KEYS[1])",View on GitHub (pinned to a96956387a)
Solutions
- Inspect `TYPE oauth:refresh:<token>` in Redis; it must be a string holding JSON
- Delete or fix the malformed key so the next refresh attempt can repopulate it
- Audit for seed scripts or consoles writing these keys outside the Edge code path
Defensive patterns
Strategy: type-guard
Validate before calling
// Before parsing a stored value, confirm it is the expected string type
const raw = await redisGet(`oauth:refresh:${token}`);
if (typeof raw !== 'string') {
// delete the malformed key / require re-login instead of crashing
} Type guard
function isStoredString(v: unknown): v is string {
return typeof v === 'string';
} Try / catch
try {
await beginRefreshAttempt(token, id);
} catch (e) {
if (e instanceof Error && e.message === 'Redis returned an invalid stored value') {
// quarantine/delete the key; user must re-authenticate
} else throw e;
} Prevention
- Keep all writes to oauth:refresh:* as JSON strings via the standard code path
- Periodically audit TYPE of oauth keys to catch drift from manual edits
When it happens
Trigger: The consumed `oauth:refresh:<token>` value being absent, boolean false, or a non-string Redis type when the script path returns `{1, value}` with a non-string `value` (e.g. after manual console edits or a format migration gone wrong).
Common situations: Manual Redis console edits writing numbers/other types; a partially applied key-format migration; cross-environment key collisions between dev and prod sharing a database.
Related errors
- Redis returned malformed JSON
- Redis not configured
- Redis HTTP ${resp.status}
- Redis EVAL failed: ${data.error}
- Redis EVAL returned an invalid response
AI-assisted analysis of koala73/worldmonitor@a96956387a (2026-08-27).
Data as JSON: /api/errors/595c7662bc592a22.
Report an issue: GitHub.