{"record":{"id":"c114d70ddccd99a2","repo":"koala73/worldmonitor","slug":"redis-command-error-data-error","errorCode":null,"errorMessage":"Redis command error: ${data.error}","messagePattern":"Redis command error: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"server/_shared/redis.ts","lineNumber":194,"sourceCode":"    const { sidecarCacheGet } = await import('./sidecar-cache');\n    return sidecarCacheGet(key);\n  }\n  const url = process.env.UPSTASH_REDIS_REST_URL;\n  const token = process.env.UPSTASH_REDIS_REST_TOKEN;\n  if (!url || !token) return null;\n  const resp = await fetch(`${url}/`, {\n    method: 'POST',\n    headers: {\n      Authorization: `Bearer ${token}`,\n      'Content-Type': 'application/json',\n      'User-Agent': 'worldmonitor-server/1.0 (redis)',\n    },\n    body: JSON.stringify(['GET', key]),\n    signal: AbortSignal.timeout(resolvePipelineTimeoutMs(timeoutMs)),\n  });\n  if (!resp.ok) throw new Error(`Redis HTTP ${resp.status}`);\n  const data = (await resp.json()) as { result?: string | null; error?: string };\n  if (data.error) throw new Error(`Redis command error: ${data.error}`);\n  if (!data.result) return null;\n  return unwrapEnvelope(JSON.parse(data.result)).data;\n}\n\n/**\n * Read a key's value as a raw Upstash string — no JSON.parse, no envelope unwrap.\n * Use when a seeder stores a bare scalar (e.g., a snapshot_id pointer) via\n * `['SET', key, bareString]` without JSON.stringify. getCachedJson() on these\n * keys silently returns null because JSON.parse throws on unquoted strings,\n * and the try/catch swallows the error.\n *\n * Always uses the raw (unprefixed) key — matches the seed-script write path\n * (seeders don't know about the Vercel env-prefix scheme).\n */\nexport async function getCachedRawString(key: string): Promise<string | null> {\n  if (process.env.LOCAL_API_MODE === 'tauri-sidecar') {\n    const { sidecarCacheGet } = await import('./sidecar-cache');\n    const v = sidecarCacheGet(key);","sourceCodeStart":176,"sourceCodeEnd":212,"githubUrl":"https://github.com/koala73/worldmonitor/blob/9361220cc013571781071f0206e4d80fd14b2f7f/server/_shared/redis.ts#L176-L212","documentation":"After a successful HTTP response, getLargeRawJson inspects the Upstash response body's error field and throws 'Redis command error: <detail>' when Upstash accepted the request but the Redis command itself failed. This distinguishes command-level failures (wrong type, OOM, script errors) from HTTP-level problems. Callers should treat it as Redis being unable to serve this key.","triggerScenarios":"Upstash returns 200 with { error: ... }, e.g. WRONGTYPE because the key holds a non-string value, an OOM/permission denial, or a malformed command — any body-level error string returned by the REST API for GET key.","commonSituations":"A key written by another code path as a hash/list/set but read here as a string (WRONGTYPE); a seed script wrote a different envelope; Upstash database rules or ACLs denying the command; corrupted key data after manual flush/import.","solutions":["Read the detail after the colon: WRONGTYPE means the key's Redis type does not match GET — inspect with TYPE and read via the matching command","Check what wrote the key; align reader and writer on the same Redis type and envelope format","Verify database ACLs/permissions allow GET on the key in the Upstash console","Delete and re-seed the key if its contents are corrupt or from an incompatible schema version"],"exampleFix":"// before\nconst data = await getLargeRawJson('canonical:mil');\n// after\nlet data;\ntry { data = await getLargeRawJson('canonical:mil'); }\ncatch (e) {\n  if (String(e).includes('WRONGTYPE')) await reseedKey('canonical:mil');\n  else throw e;\n}","handlingStrategy":"try-catch","validationCode":"// Before GET, confirm the key's type matches expectations\nconst type = await getRawKeyType(key); // e.g. via TYPE command\nif (type !== 'string') reseedOrUseMatchingReader(key, type);","typeGuard":"function isRedisCommandError(e: unknown): e is Error {\n  return e instanceof Error && e.message.startsWith('Redis command error:');\n}","tryCatchPattern":"try {\n  data = await getLargeRawJson(key);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('WRONGTYPE')) {\n    await reseedKey(key);\n    data = await getLargeRawJson(key);\n  } else throw e;\n}","preventionTips":["Keep writer and reader Redis types aligned (string GET vs hash/list commands)","Audit seed scripts for keys that collide with JSON-string keys","Check Upstash ACLs allow the commands your code issues","Include the key name in the thrown error context for faster diagnosis"],"tags":["redis","upstash","wrongtype","command-error"],"backgroundTag":"redis-command-error","analyzedSha":"9361220cc013571781071f0206e4d80fd14b2f7f","analyzedAt":"2026-09-01T10:32:37.851Z","contentChangedAt":"2026-09-01T10:32:37.851Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}