Skip to content

correct IndexError caused by empty list of chunks when performing chu… - #202

Merged
Ahmath-Gadji merged 1 commit into
devfrom
fix/chunking_list_out_of_range_error
Jan 14, 2026
Merged

correct IndexError caused by empty list of chunks when performing chu…#202
Ahmath-Gadji merged 1 commit into
devfrom
fix/chunking_list_out_of_range_error

Conversation

@Ahmath-Gadji

@Ahmath-Gadji Ahmath-Gadji commented Jan 12, 2026

Copy link
Copy Markdown
Collaborator

This PR makes the chunking pipeline more robust by:

  • Passing filename explicitly to avoid the metadata extraction issue in IndexError: list index out of range in chunker contextualization #201
  • Logging warnings when no chunks are generated
  • Fixing false-positive filtering of informative images:
    • Uninformative images have the exact format: """<image_description>\n\n[Image Placeholder]\n\n</image_description>"""
    • The old filter checked if [Image Placeholder] appeared anywhere in the description, incorrectly removing informative images where the VLM happened to include that phrase
    • The new filter uses exact pattern matching to only remove true placeholders

Summary by CodeRabbit

  • Bug Fixes

    • Returns empty results and logs a warning when no chunks are produced, preventing downstream errors.
    • Case-insensitive detection of image placeholders during markdown processing to avoid false positives.
  • Improvements

    • Filenames are preserved and propagated through the chunking/contextualization pipeline for clearer metadata and messages.
    • More consistent logging and contextualization behavior across the pipeline.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitai Bot commented Jan 12, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds explicit filename propagation through chunking and contextualization, makes image-placeholder checks case-insensitive, and adds explicit handling/logging for empty-chunk cases. Method signatures for contextualization and internal application were updated and callers now pass filename from document metadata.

Changes

Cohort / File(s) Change Summary
Filename Parameter Propagation
openrag/components/indexer/chunker/chunker.py
Added filename: str = "" parameter to contextualize_chunks and _apply_contextualization; callers (including split_document) extract and pass filename through the chunking/contextualization pipeline.
Empty Chunk Handling & Flow
openrag/components/indexer/chunker/chunker.py
_get_chunks now returns [] and logs a warning when no chunks are produced; split_document returns early with [] when no chunks exist to avoid further processing.
Image Placeholder Detection
openrag/components/indexer/chunker/chunker.py, openrag/consts.py
Introduced IMAGE_PLACEHOLDER constant in consts.py; _prepare_md_elements performs case-insensitive checks (IMAGE_PLACEHOLDER.lower() in e.content.lower()) to skip placeholder images.
Logging & Signature Adjustments
openrag/components/indexer/chunker/chunker.py
Adjusted logging messages and contextualization flow to consistently include filename in warnings/formatting; updated public/internal method signatures accordingly.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped through chunks with filename in tow,

Skipped phantom images that tried to show,
When chunks ran empty I warned with a hop,
Context passed clean, not a single drop,
A rabbit cheers — the pipeline's ready to go! 🎉

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 71.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title is truncated and incomplete ('correct IndexError caused by empty list of chunks when performing chu…'), making it unclear and vague about the actual changes. Complete the title to clearly describe the main change, such as 'Fix IndexError in chunking pipeline by passing filename explicitly and improving chunk validation' or a more specific summary of the primary fix.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings


📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 45861df and f84eac5.

📒 Files selected for processing (2)
  • openrag/components/indexer/chunker/chunker.py
  • openrag/consts.py
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: index-backup-restore
🔇 Additional comments (6)
openrag/consts.py (1)

6-8: LGTM!

The IMAGE_PLACEHOLDER constant is properly extracted to the constants file as suggested in past reviews, making it reusable and centralizing the definition.

openrag/components/indexer/chunker/chunker.py (5)

13-14: LGTM!

Properly imports IMAGE_PLACEHOLDER from the centralized constants file, addressing the prior review feedback.


71-76: LGTM!

The addition of the filename parameter with a default value maintains backward compatibility while enabling proper filename propagation through the contextualization flow.


140-160: LGTM!

The filename parameter is correctly added to the signature and properly passed through both the non-contextualized and contextualized code paths.


274-281: LGTM!

The empty-chunk handling is now robust: it logs a warning (appropriate for this edge case) and returns an empty list, preventing the IndexError that originally motivated this PR.


288-313: LGTM!

The filename is properly extracted from metadata and propagated through the contextualization pipeline. The conditional check on chunks ensures contextualization is only attempted when there are chunks to process, completing the fix for the original IndexError issue.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Ahmath-Gadji Ahmath-Gadji linked an issue Jan 12, 2026 that may be closed by this pull request
@Ahmath-Gadji
Ahmath-Gadji marked this pull request as ready for review January 12, 2026 14:36
@Ahmath-Gadji Ahmath-Gadji added the fix Fix issue label Jan 12, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
openrag/components/indexer/chunker/chunker.py (1)

301-313: Correct empty-chunk handling; minor log clarity improvement possible.

The empty-chunk guard correctly prevents downstream errors. However, the log message "Contextualizing chunks" is always emitted even when contextual_retrieval is False, which could be slightly misleading when reading logs.

Optional: Adjust log message for clarity
         if chunks:
-            # Apply contextualization if enabled
-            log.info(
-                "Contextualizing chunks",
-                apply_contextualization=self.contextual_retrieval,
-            )
+            # Apply contextualization if enabled
+            log.info(
+                "Applying chunk formatting",
+                contextual_retrieval=self.contextual_retrieval,
+            )
             chunks = await self._apply_contextualization(
                 chunks, lang=detected_lang, filename=filename
             )
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ce7a280 and 0344755.

📒 Files selected for processing (1)
  • openrag/components/indexer/chunker/chunker.py
🔇 Additional comments (5)
openrag/components/indexer/chunker/chunker.py (5)

69-74: LGTM!

Good addition of the filename parameter with a sensible default. This maintains backward compatibility while enabling explicit filename propagation.


138-158: LGTM!

The filename parameter is correctly propagated through to contextualize_chunks and used in chunk formatting.


167-175: Substring check vs exact match inconsistency with PR description.

The PR description states this uses "exact pattern matching," but the implementation uses in (substring check) rather than == (exact equality). While checking for the full placeholder format is a significant improvement over the previous check for just [Image Placeholder], this could still produce false positives if content contains the placeholder string embedded in larger text.

If uninformative images always have exactly this content, consider using exact equality:

Suggested fix for exact matching
         img_placeholder = (
             """<image_description>\n\n[Image Placeholder]\n\n</image_description>"""
         )
         for e in md_elements:
             if e.type in ("table", "image"):
                 if (
-                    e.type == "image" and img_placeholder.lower() in e.content.lower()
+                    e.type == "image" and e.content.strip().lower() == img_placeholder.lower()
                 ):  # skip placeholder images
                     continue

Please verify whether placeholder images always have exactly this content or may include surrounding whitespace/text.


274-281: LGTM!

This correctly addresses the IndexError issue by checking for an empty chunks list before attempting to sort. The warning log provides useful debugging information when no chunks are created.


39-39: Note: Different metadata keys used for filename.

_generate_context extracts filename from metadata.get("source", "unknown") while split_document extracts from metadata.get("filename", ""). If these metadata keys can have different values, ensure this is intentional.

@paultranvan paultranvan left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, with small remarks

Comment thread openrag/components/indexer/chunker/chunker.py Outdated
Comment thread openrag/components/indexer/chunker/chunker.py
@Ahmath-Gadji
Ahmath-Gadji force-pushed the fix/chunking_list_out_of_range_error branch from 0344755 to 45861df Compare January 14, 2026 09:31

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@openrag/components/indexer/chunker/chunker.py`:
- Around line 274-279: The code currently logs "No chunks created. Content is
empty or image is not informative." with log.info but the PR asks for a warning
level; update the logging call from log.info to log.warning (the call
referencing chunks and the log variable in chunker.py) so empty-chunk cases are
emitted as warnings instead of informational messages.
- Around line 167-175: The code currently uses substring matching ("in") to
detect placeholders via the img_placeholder string, which contradicts the PR's
requirement for exact pattern matching; update the check in chunker.py to
compare the normalized contents exactly (e.g., normalize both sides with strip()
and lower() and use equality) when inspecting md_elements entries (use e.type
and e.content) so only true placeholders are skipped, and move the
img_placeholder value out to a shared constant (e.g., IMAGE_PLACEHOLDER) in the
constants module and import it into the chunker to avoid duplicating the
literal.
🧹 Nitpick comments (1)
openrag/components/indexer/chunker/chunker.py (1)

31-39: Potential IndexError if contextualize_chunks is called directly with an empty list.

While the current internal flow guards against this (via the len(chunks) < 2 check in _apply_contextualization), the public method contextualize_chunks would raise an IndexError at line 39 and 77 if called directly with an empty list.

Consider adding a guard at the start of contextualize_chunks:

     async def contextualize_chunks(
         self,
         chunks: list[Document],
         lang: Literal["fr", "en"] = "en",
         filename: str = "",
     ) -> list[Document]:
         """Contextualize a list of document chunks."""
+        if not chunks:
+            return []
         try:
             first_chunks = chunks[:2]

Also note that _generate_context extracts filename from first_chunks[0].metadata.get("source", "unknown") (line 39), but the filename parameter passed to contextualize_chunks is only used for progress display and formatting—not in _generate_context. This creates a subtle inconsistency where the context generation uses a different filename source than the chunk formatting.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0344755 and 45861df.

📒 Files selected for processing (1)
  • openrag/components/indexer/chunker/chunker.py
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: index-backup-restore
🔇 Additional comments (3)
openrag/components/indexer/chunker/chunker.py (3)

69-108: LGTM!

The filename parameter addition properly propagates through the contextualization flow, enabling explicit filename handling for progress descriptions and chunk formatting.


138-158: LGTM!

The filename parameter is correctly propagated to both the non-contextual formatting path and the contextualizer, ensuring consistent chunk formatting regardless of whether contextualization is enabled.


281-311: LGTM!

The changes properly address the original IndexError by:

  1. Extracting filename safely with a default empty string
  2. Checking for empty chunks before proceeding to contextualization
  3. Returning early with an empty list when no chunks are created

This makes the pipeline more robust against empty-chunk scenarios.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines 167 to 175
img_placeholder = (
"""<image_description>\n\n[Image Placeholder]\n\n</image_description>"""
)
for e in md_elements:
if e.type in ("table", "image"):
if (
e.type == "image" and "[Image Placeholder]" in e.content
e.type == "image" and img_placeholder.lower() in e.content.lower()
): # skip placeholder images
continue

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

The implementation uses substring matching, not exact pattern matching as described in the PR.

The PR objective states this should use "exact pattern matching so only true placeholders are removed," but the code still uses in (substring check). If exact matching is intended, this should use equality comparison:

-                if (
-                    e.type == "image" and img_placeholder.lower() in e.content.lower()
-                ):  # skip placeholder images
+                if (
+                    e.type == "image" and e.content.strip().lower() == img_placeholder.lower()
+                ):  # skip placeholder images

If substring matching is intentional, the case-insensitive check could still filter out informative images if the VLM output happens to contain the phrase [image placeholder] within actual descriptive content.

Additionally, consider moving img_placeholder to a constants file as suggested in prior review.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
img_placeholder = (
"""<image_description>\n\n[Image Placeholder]\n\n</image_description>"""
)
for e in md_elements:
if e.type in ("table", "image"):
if (
e.type == "image" and "[Image Placeholder]" in e.content
e.type == "image" and img_placeholder.lower() in e.content.lower()
): # skip placeholder images
continue
img_placeholder = (
"""<image_description>\n\n[Image Placeholder]\n\n</image_description>"""
)
for e in md_elements:
if e.type in ("table", "image"):
if (
e.type == "image" and e.content.strip().lower() == img_placeholder.lower()
): # skip placeholder images
continue
🤖 Prompt for AI Agents
In `@openrag/components/indexer/chunker/chunker.py` around lines 167 - 175, The
code currently uses substring matching ("in") to detect placeholders via the
img_placeholder string, which contradicts the PR's requirement for exact pattern
matching; update the check in chunker.py to compare the normalized contents
exactly (e.g., normalize both sides with strip() and lower() and use equality)
when inspecting md_elements entries (use e.type and e.content) so only true
placeholders are skipped, and move the img_placeholder value out to a shared
constant (e.g., IMAGE_PLACEHOLDER) in the constants module and import it into
the chunker to avoid duplicating the literal.

Comment thread openrag/components/indexer/chunker/chunker.py
@Ahmath-Gadji
Ahmath-Gadji force-pushed the fix/chunking_list_out_of_range_error branch from 45861df to f84eac5 Compare January 14, 2026 10:11
@Ahmath-Gadji
Ahmath-Gadji merged commit 38e74cf into dev Jan 14, 2026
3 checks passed
@Ahmath-Gadji
Ahmath-Gadji deleted the fix/chunking_list_out_of_range_error branch January 14, 2026 10:30
@coderabbitai coderabbitai Bot mentioned this pull request Jan 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fix Fix issue

Projects

None yet

Development

Successfully merging this pull request may close these issues.

IndexError: list index out of range in chunker contextualization

2 participants