Skip to content

ROB: Do not crash when the outlines entry is not a dictionary - #4023

Merged
stefan6419846 merged 1 commit into
py-pdf:mainfrom
RavSinghChandan:outlines-catalog-not-a-dictionary
Aug 28, 2026
Merged

stefan6419846 merged 1 commit into
py-pdf:mainfrom
RavSinghChandan:outlines-catalog-not-a-dictionary

Conversation

@RavSinghChandan

Copy link
Copy Markdown
Contributor

_get_outline casts /Outlines to a DictionaryObject and tests /First membership on the result:

>>> reader.outline
TypeError: argument of type 'NumberObject' is not iterable

The function already returns an empty outline for a null entry, so one it cannot read is reported and takes the same path.

This is a different line from #4018, which guards a node inside the walk rather than the catalog entry itself.

Reverting the change fails the three new tests

Comment thread pypdf/_doc_common.py Resolved
Comment thread tests/test_doc_common.py Resolved
Comment thread tests/test_doc_common.py Resolved
@codecov

codecov Bot commented Aug 26, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.02%. Comparing base (a692202) to head (51fde2c).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4023      +/-   ##
==========================================
+ Coverage   98.01%   98.02%   +0.01%     
==========================================
  Files          57       57              
  Lines       11162    11165       +3     
  Branches     2098     2099       +1     
==========================================
+ Hits        10940    10945       +5     
+ Misses        124      123       -1     
+ Partials       98       97       -1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@RavSinghChandan
RavSinghChandan force-pushed the outlines-catalog-not-a-dictionary branch from 60d6600 to 275aa0f Compare August 27, 2026 02:37
@RavSinghChandan

Copy link
Copy Markdown
Contributor Author

Not a behavioural change as far as I can tell. A direct NullObject returns from the branch above, an indirect one is resolved by get_object() before either check, and a dictionary lookup gives back NullObject rather than a bare None. I've added a test covering the direct and indirect null cases so it's pinned.

@RavSinghChandan

Copy link
Copy Markdown
Contributor Author

Added the IDs.

@RavSinghChandan

Copy link
Copy Markdown
Contributor Author

You're right, that name described my change rather than the behaviour. Renamed.

@RavSinghChandan
RavSinghChandan force-pushed the outlines-catalog-not-a-dictionary branch 2 times, most recently from 02fc12c to 3b7370d Compare August 27, 2026 14:42
@RavSinghChandan

Copy link
Copy Markdown
Contributor Author

Not a behavioural change as far as I can tell. A direct NullObject returns from the branch above, an indirect one is resolved by get_object() before either check, and a dictionary lookup gives back NullObject rather than a bare None. I've added a test covering the direct and indirect null cases so it's pinned.

@RavSinghChandan

Copy link
Copy Markdown
Contributor Author

You're right, that name described my change rather than the behaviour. Renamed.

@RavSinghChandan
RavSinghChandan force-pushed the outlines-catalog-not-a-dictionary branch from 3b7370d to c19fa36 Compare August 28, 2026 03:42

@stefan6419846 stefan6419846 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.

It seems like we need another final round of resolving the merge conflicts here to get this merged. There were too many PRs touching the same file section.

_get_outline casts /Outlines to a DictionaryObject and tests /First membership
on the result, so a file where that entry holds a number, a string or an array
raised 'TypeError: argument of type NumberObject is not iterable' from
reader.outline.

The dropped is_null_or_none call covered three cases, all still handled: a
direct NullObject returns from the branch above it, an indirect reference is
resolved by get_object() before either check, and a bare None cannot come out
of a dictionary lookup. Both null paths have a test.
@RavSinghChandan
RavSinghChandan force-pushed the outlines-catalog-not-a-dictionary branch from c19fa36 to 51fde2c Compare August 28, 2026 09:48
@RavSinghChandan

Copy link
Copy Markdown
Contributor Author

it's two files now with no unrelated changes, and it's mergeable.

@stefan6419846
stefan6419846 merged commit b17dee7 into py-pdf:main Aug 28, 2026
25 of 34 checks passed
usmanmateen added a commit to usmanmateen/pypdf that referenced this pull request Oct 10, 2026
Since 6.17.0, reader.outline raised "AttributeError: 'NoneType' object has
no attribute 'get_object'" when /Outlines referenced an object that is
missing or free in the xref table, as in PDF files exported by Google
apps such as Slides and Sheets. Such a reference resolves to None, which
the is_null_or_none check dropped in py-pdf#4023 covered.
usmanmateen added a commit to usmanmateen/pypdf that referenced this pull request Oct 10, 2026
Since 6.17.0, reader.outline raised "AttributeError: 'NoneType' object has
no attribute 'get_object'" when /Outlines referenced an object that is
missing or free in the xref table, as in PDF files exported by Google
apps such as Slides and Sheets. Such a reference resolves to None, which
the is_null_or_none check dropped in py-pdf#4023 covered.
stefan6419846 pushed a commit that referenced this pull request Oct 13, 2026
Since 6.17.0, reader.outline raised "AttributeError: 'NoneType' object has
no attribute 'get_object'" when /Outlines referenced an object that is
missing or free in the xref table, as in PDF files exported by Google
apps such as Slides and Sheets. Such a reference resolves to None, which
the is_null_or_none check dropped in #4023 covered.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants