Fix unprotected JSON.parse in Redis.getObject() crashing viewer stats processing - #7537
Conversation
… processing Wrap JSON.parse in getObject() with try/catch and add a null guard in processViewerStats() so corrupted Redis entries are skipped and cleaned up instead of crashing the entire batch job.
There was a problem hiding this comment.
Pull request overview
Defensive hardening of viewer stats batch processing so a corrupted Redis entry doesn’t crash processViewerStats() and block persistence of subsequent viewer stats.
Changes:
- Add
try/catcharoundJSON.parseinRedis.getObject()and returnnullon parse failure. - Skip and delete invalid viewer stats Redis keys during
processViewerStats()when stats cannot be loaded. - Add warning logs for parse failures / invalid viewer stats entries.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| server/core/lib/stats/shared/video-viewer-stats.ts | Skip/delete invalid viewer stats entries during batch processing to prevent aborting the whole loop. |
| server/core/lib/redis.ts | Catch JSON.parse failures in getObject() and log/return null instead of throwing. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @@ -156,6 +156,12 @@ export class VideoViewerStats { | |||
| for (const key of allKeys) { | |||
| const stats: LocalViewerStats = await this.getLocalVideoViewerByKey(key) | |||
There was a problem hiding this comment.
stats can now legitimately be null (e.g. parse failure in Redis.getObject()), but it’s still typed as LocalViewerStats here. Updating the return types of getLocalVideoViewerByKey/getLocalVideoViewer (and this local variable) to LocalViewerStats | null would make the null-handling explicit and prevent accidental property access elsewhere without a guard.
| const stats: LocalViewerStats = await this.getLocalVideoViewerByKey(key) | |
| const stats: LocalViewerStats | null = await this.getLocalVideoViewerByKey(key) |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Description
Noticed while reading through the viewer stats processing code that
Redis.getObject()callsJSON.parse()without any error handling. On a self-hosted instance, if a Redis value gets corrupted (partial write during a crash, data from a different PeerTube version, manual Redis intervention), the unhandled parse error propagates up throughgetLocalVideoViewerByKey()inprocessViewerStats().Since
getLocalVideoViewerByKey()is called outside the inner try/catch block (line 157, before the transaction at line 164), the exception is caught by the outer catch at line 181 — which exits the entireforloop. This means a single corrupted entry blocks all remaining viewer stats from being persisted to the database.Minimal reproduction:
The same codebase already handles this correctly in
server/core/models/server/plugin.ts(lines 209–213):Before: One corrupted Redis viewer stats entry crashes
processViewerStats(), preventing all remaining entries from being saved to the database.After: Corrupted entries are logged, cleaned up from Redis, and skipped. The remaining entries are processed normally.
Changes
redis.ts: WrapJSON.parseingetObject()with try/catch, log warning, return nullvideo-viewer-stats.ts: Add null check inprocessViewerStats()loop — log, delete the invalid key, and continueRelated issues
Has this been tested?
JSON.parseand the fix returns null insteadplugin.tsScreenshots
N/A