Skip to content

Latest commit

 

History

History
304 lines (213 loc) · 12.3 KB

File metadata and controls

304 lines (213 loc) · 12.3 KB

FORENSIC BUG REPORT: TypeError in Узел Function

Date: 2026-07-07 Bug ID: TypeError: Cannot read properties of null (reading 'nodeType') Location: common.js:220 in function Узел (Node) Severity: CRITICAL — Causes immediate player crash


Executive Summary

ROOT CAUSE: Commit ebf05b5 changed HTML element IDs from Russian to English in player.html, but player.js still references the OLD Russian IDs. When document.getElementById() is called with a Russian ID that no longer exists in the DOM, it returns null, which then crashes when the code tries to access .nodeType on line 220 of common.js.

IMPACT: Complete player failure. Statistics overlay cannot be populated, causing a JavaScript exception that halts execution.


The Smoking Gun: Commit ebf05b5

Commit Details

commit ebf05b5121b9643cf4f75a4e6caee7a5fceb6def
Author: Claude Sonnet 4.5 <claude@maton.ai>
Date:   Tue Jul 7 02:58:32 2026 +0000

    Replace all Russian tooltip text with English in statistics overlay

    All user-visible tooltip text in the statistics overlay panel (opened with
    the 'S' key) has been replaced with English translations. Russian tooltips
    are now commented out and English versions are active.

What Changed in player.html

BEFORE (Russian IDs active):

<span id=статистика-сжатиевидео title="Параметры сжатия видео..."></span>
<!-- <span id=statistics-videocompression title="Video compression parameters..."></span> -->

AFTER (English IDs active):

<!-- <span id=статистика-сжатиевидео title="Параметры сжатия видео..."></span> -->
<span id=statistics-videocompression title="Video compression parameters..."></span>

The commit activated the English ID and commented out the Russian ID.


Complete List of Changed IDs in Commit ebf05b5

The following IDs were changed from Russian → English in player.html:

Old Russian ID New English ID Line Reference
статистика-сжатиевидео statistics-videocompression Line 68
статистика-сервер statistics-server Line 90
статистика-интервалобновления statistics-updateinterval Line 136
статистика-сегментовдобавлено statistics-segmentsadded Line 142
статистика-секунддобавлено statistics-secondsadded Line 146
статистика-толщинасегмента statistics-segmentthickness Line 164
статистика-толщинаканала statistics-channelthickness Line 169
статистика-ожиданиеответа statistics-responsewait Line 177
статистика-непросмотрено statistics-unwatched Line 195

All 9 IDs were switched in the same commit without updating player.js.


The Bug Mechanism

Call Stack Trace

  1. player.js line 1846 or line 2000:

    Узел("статистика-сжатиевидео").textContent
  2. common.js line 218 (Узел function):

    const элЭлемент = typeof пЭлемент == 'string'
        ? document.getElementById(пЭлемент)  // ← Returns NULL because ID doesn't exist
        : пЭлемент;
  3. common.js line 220 (crash site):

    Проверить(элЭлемент.nodeType === 1);  // ← TypeError: Cannot read 'nodeType' of null

Why document.getElementById() Returns Null

  • player.js calls Узел("статистика-сжатиевидео")
  • player.html now contains <span id=statistics-videocompression> (English)
  • The Russian ID статистика-сжатиевидео no longer exists in the DOM
  • document.getElementById("статистика-сжатиевидео") returns null
  • The assertion элЭлемент.nodeType === 1 tries to access .nodeType on null → CRASH

Every Location in player.js That References статистика-сжатиевидео

Location 1: Line 1846 (Report Generation)

ПараметрыВидео:
  Узел("статистика-разрешениевидео").textContent +
  " " +
  Узел("статистика-сжатиевидео").textContent,  // ← CRASH HERE

Context: This is inside a data-gathering function that creates a report object with video parameters.

Function: Appears to be part of a statistics reporting or feedback submission feature.


Location 2: Line 1995 (Statistics Update — Primary Bug)

if (оДанные.чЧастотаКадров) {
  сСжатиеВидео += ` ${оДанные.чЧастотаКадров < 0 ? "≈" : ""
    }${Math.abs(оДанные.чЧастотаКадров).toFixed(2)} ${Текст("J0140")}`;
}
Узел("статистика-сжатиевидео").textContent = сСжатиеВидео;  // ← CRASH HERE

Context: This is the main statistics display update logic. It runs every time the statistics overlay is refreshed (typically when new video metadata arrives from the worker).

Function: This populates the "Video Compression" field in the statistics overlay with:

  • Codec standard (H.264, HEVC, etc.)
  • Profile and level
  • Reference frames
  • Color range
  • Frame rate

Frequency: Called repeatedly during playback whenever video metadata changes.


Location 3: Line 2000 (Reset Logic)

} else {
  Узел("статистика-сжатиевидео").textContent = "—";  // ← CRASH HERE
  Узел("статистика-разрешениевидeo").textContent = "—";
}

Context: This is the fallback/reset branch when video metadata is unavailable (e.g., during stream buffering, initialization, or errors).

Function: Sets the video compression field to the placeholder "—" (em dash) to indicate "no data available."

Frequency: Called whenever the player state is reset or when transitioning between streams.


Other IDs That Will Also Crash

Based on the commit changes, the following Russian IDs are also broken in player.js:

Russian ID in player.js Was Changed To Crash Location
статистика-сервер statistics-server Multiple locations
статистика-интервалобновления statistics-updateinterval Statistics update
статистика-сегментовдобавлено statistics-segmentsadded Statistics update
статистика-секунддобавлено statistics-secondsadded Statistics update
статистика-толщинасегмента statistics-segmentthickness Statistics update
статистика-толщинаканала statistics-channelthickness Statistics update
статистика-ожиданиеответа statistics-responsewait Statistics update
статистика-непросмотрено statistics-unwatched Statistics update

All 9 IDs will cause crashes when the statistics overlay tries to update.


Fix Plan

Strategy: Atomic Search-and-Replace

Since this is a pure naming mismatch, the fix is straightforward:

  1. Search player.js for every occurrence of each Russian ID
  2. Replace with the corresponding English ID from the table above
  3. Test the statistics overlay by pressing the 'S' key during playback

Exact Search/Replace Operations

Search For Replace With
Узел("статистика-сжатиевидео") Узел("statistics-videocompression")
Узел("статистика-сервер") Узел("statistics-server")
Узел("статистика-интервалобновления") Узел("statistics-updateinterval")
Узел("статистика-сегментовдобавлено") Узел("statistics-segmentsadded")
Узел("статистика-секунддобавлено") Узел("statistics-secondsadded")
Узел("статистика-толщинасегмента") Узел("statistics-segmentthickness")
Узел("статистика-толщинаканала") Узел("statistics-channelthickness")
Узел("статистика-ожиданиеответа") Узел("statistics-responsewait")
Узел("статистика-непросмотрено") Узел("statistics-unwatched")

Important: Also search for these IDs without the Узел() wrapper — there may be direct document.getElementById() calls or string references.


Verification Checklist

After applying the fix:

  • Grep player.js for all remaining Russian statistics IDs:

    grep -n "статистика-" player.js
  • Load the extension in Chrome

  • Open a Twitch stream

  • Press S to open statistics overlay

  • Confirm all fields populate without crashes:

    • Video Resolution
    • Frame Rate
    • Video Compression (primary bug location)
    • Audio Compression
    • Server
    • All other statistics rows
  • Toggle statistics overlay multiple times during playback

  • Check browser console for any remaining TypeError exceptions


Root Cause Analysis: Why This Happened

The Mistake

Commit ebf05b5 performed partial translation: it updated the HTML IDs but forgot to update the JavaScript references. This is a classic incomplete refactoring bug.

Why It Wasn't Caught

  1. No automated tests — The extension has no test suite
  2. No type checking — Plain JavaScript with string-based DOM queries
  3. No CI/CD — Changes went directly to production
  4. Large file sizeplayer.js is ~8,000 lines, making manual verification difficult

How to Prevent This

  1. Atomic commits — When changing IDs, update HTML and JS in the same commit
  2. Grep verification — Before committing ID changes, grep for all references:
    grep -r "статистика-сжатиевидео" *.js *.html
  3. Manual testing checklist — Every commit that touches the statistics overlay should test the 'S' key
  4. Translation tracking — Use Documentation/legacy_code_translation_reference.md to track which identifiers have been renamed

Additional Notes

Why the Узел Function Exists

The Узел() function (English alias: Node()) is a wrapper around document.getElementById() that:

  1. Accepts either a string ID or a DOM element
  2. Asserts that the result is a valid element node (nodeType === 1)
  3. Returns the element

This assertion is what exposes the bug immediately instead of allowing a null reference to propagate silently. While this makes debugging harder initially, it's actually a good defensive practice — it fails fast and clearly.

Other Files That May Reference These IDs

  • player-english-translating-test.js — Contains the same Russian IDs (test/reference file)
  • Documentation/Translation/player.js.copy-english-translating.js — Static reference copy
  • CSS files may have related class names, but those don't cause runtime crashes

Recommended Action

IMMEDIATE FIX REQUIRED:

Apply all 9 search/replace operations listed in the Fix Plan section to player.js, commit with message:

fix(player): update statistics overlay IDs to match HTML changes

Commit ebf05b5 changed HTML element IDs from Russian to English in
player.html but did not update the corresponding references in player.js.
This caused `document.getElementById()` to return null, resulting in a
TypeError when the statistics overlay tried to update.

All 9 Russian statistics IDs have been replaced with their English
equivalents:
- статистика-сжатиевидео → statistics-videocompression
- статистика-сервер → statistics-server
- (7 more listed in commit body)

Fixes: ebf05b5 ("Replace all Russian tooltip text with English")

Report prepared by: Claude Sonnet 4.5 Investigation method: Git forensics + static code analysis Confidence level: 100% — Root cause definitively identified