Skip to content

fix(toc_extractor): break exits only inner block loop, causing spurious page iterations when body_median==0.0 #267

Closed

Description

@piyushmakhija28

Summary

In _detect_headers(), when body_median == 0.0 (e.g., image-only pages with empty font metrics), the break at line 267 exits only the inner for block in page.blocks loop. The outer for page in doc.pages loop continues iterating every remaining page, re-entering and immediately breaking the inner loop N more times — wasting computation and creating a latent code trap.

Root Cause

ingestion/toc_extractor.py around line 264–275:

for page in doc.pages:           # outer loop
    ...
    body_median = _median_font(page.blocks)
    for block in page.blocks:    # inner loop
        if body_median == 0.0:
            break                # ← exits ONLY the inner loop
        # header detection logic...
    # outer loop continues to next page

The intent is clearly to skip the rest of the function when body_median == 0.0 (the document has no usable font metadata). But break only exits the innermost loop — the outer for page loop fires N more iterations.

Failure Scenario

  1. A 200-page image-only PDF (e.g. scanned document) is processed.
  2. Every page has body_median == 0.0 (no font metadata extracted by PyMuPDF).
  3. _detect_headers iterates all 200 pages; for each page: enters inner loop, hits body_median==0.0, breaks immediately.
  4. For a 200-page document with 20 blocks each: 200 × 20 = 4,000 inner-loop iterations execute instead of 0.
  5. A future developer adding code between lines 267 and 275 (inside the inner loop, below the break) will accidentally execute it once per page.

Proposed Fix

Use a continue/flag or restructure to exit both loops:

for page in doc.pages:
    body_median = _median_font(page.blocks)
    if body_median == 0.0:
        continue   # skip this page entirely, or use `return raw` to exit early

    for block in page.blocks:
        # header detection logic (body_median is guaranteed > 0 here)
        ...

Or use return raw early if no page in the document has font data:

if not any(_median_font(p.blocks) > 0.0 for p in doc.pages):
    return []  # no usable font metadata in document

Activity

  1. piyushmakhija28 commented on Jun 21, 2026

    @piyushmakhija28
    ContributorAuthor

    Fixed in PR #280 (Sprint R3/R4: fix(sprint-r3): root-cause fixes for all 39 bugs from code review round 3 + Sprint R4 round 4)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingcode-reviewFound via automated code reviewpriority: mediumFunctional error with workaround

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions