spring-projects/spring-ai · warning

Skipping paragraph titled '<title>' because it has an invali

Error message

Skipping paragraph titled '<title>' because it has an invalid start page number: <pageNumber>

What it means

The PDF paragraph reader (PDFBox-based TOC/paragraph extraction) encountered a paragraph whose start page number is less than 1, i.e. invalid for a 1-indexed PDF page model. Instead of failing, it skips the paragraph, logs this warning, and returns an empty string for the text range, so that paragraph's content is silently missing from the extracted document.

Source

Thrown at document-readers/spring-ai-pdf-document-reader/src/main/java/org/springframework/ai/reader/pdf/ParagraphPdfDocumentReader.java:181

		return document;
	}

	protected void addMetadata(Paragraph from, Paragraph to, Document document) {
		document.getMetadata().put(METADATA_TITLE, from.title());
		document.getMetadata().put(METADATA_START_PAGE, from.startPageNumber());
		document.getMetadata().put(METADATA_END_PAGE, from.endPageNumber());
		document.getMetadata().put(METADATA_LEVEL, from.level());
		if (this.resourceFileName != null) {
			document.getMetadata().put(METADATA_FILE_NAME, this.resourceFileName);
		}
	}

	public String getTextBetweenParagraphs(Paragraph fromParagraph, Paragraph toParagraph) {

		if (fromParagraph.startPageNumber() < 1) {
			if (logger.isWarnEnabled()) {
				logger.warn("Skipping paragraph titled '" + fromParagraph.title()
						+ "' because it has an invalid start page number: " + fromParagraph.startPageNumber());
			}
			return "";
		}

		// Page started from index 0, while PDFBOx getPage return them from index 1.
		int startPage = fromParagraph.startPageNumber() - 1;
		int endPage = toParagraph.startPageNumber() - 1;

		if (fromParagraph == toParagraph || endPage < startPage) {
			endPage = startPage;
		}

		try {

			StringBuilder sb = new StringBuilder();

			var pdfTextStripper = new PDFLayoutTextStripperByArea();

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Inspect the PDF's outline/bookmarks with a PDF inspector and repair or regenerate the source PDF.
  2. Fall back to PagePdfDocumentReader, which reads by explicit page ranges and ignores the TOC structure.
  3. Pre-validate the extracted paragraphs and filter out ones with startPageNumber < 1 before calling getTextBetweenParagraphs.
  4. If the paragraph content matters, extract its text via an alternate path (e.g. PDFTextStripper over the whole document) and match by title.

Example fix

// before: unguarded extraction
String text = reader.getTextBetweenParagraphs(from, to);
// after: validate first
if (from.startPageNumber() >= 1) {
    String text = reader.getTextBetweenParagraphs(from, to);
} else {
    logger.warn("Skipping invalid paragraph: " + from.title());
}
Defensive patterns

Strategy: fallback

Validate before calling

if (paragraph.startPageNumber() < 1) {
    logger.warn("Invalid paragraph '" + paragraph.title() + "', skipping");
    return "";
}

Type guard

boolean hasValidPageRange(Paragraph p) {
    return p != null && p.startPageNumber() >= 1;
}

Try / catch

// getTextBetweenParagraphs does not throw; check for empty result
String text = reader.getTextBetweenParagraphs(from, to);
if (text.isEmpty()) {
    // fall back to whole-document extraction by page range
    text = pageReader.get(p1, p2);
}

Prevention

When it happens

Trigger: Calling getTextBetweenParagraphs (via docText) on a Paragraph whose startPageNumber() returns 0 or negative — typically a malformed or synthetic Paragraph produced by parsing an unusual PDF outline/TOC (e.g. page labels that don't resolve to real pages).

Common situations: Reading PDFs with non-standard or corrupted bookmarks/TOC structures; PDFs produced by generators that emit bogus page references in the document outline; relying on ParagraphPdfDocumentReader where the PDF's logical structure does not match physical pages.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11). Data as JSON: /api/errors/01347dbabd5d3d60. Report an issue: GitHub.