Skip to content

SettingsFrame.settings passes a Schema class to ListField's item_type instead of a SchemaField #459

Description

@JarryShaw

SettingsFrame.settings passes a Schema class where ListField expects a field instance, with the resulting type error silenced by a # type: ignore[arg-type].

The site

pcapkit/protocols/schema/application/httpv2.py:283-285:

#: Settings.
settings: 'list[SettingPair]' = ListField(
    length=lambda pkt: pkt['__length__'],
    item_type=SettingPair,  # type: ignore[arg-type]
)

Every other ListField in the tree wraps its schema item in a SchemaField — for example pcapkit/protocols/schema/transport/tcp.py:393 is item_type=SchemaField(length=8, schema=SACKBlock), and internet/hip.py:260, internet/mh.py:535 and transport/sctp.py:702 follow the same shape.

Confirmed on e2d8ed6d1

SettingPair is a SchemaMeta -> Schema subclass: True
ListField._item_type is: SchemaMeta

So _item_type holds the metaclass-produced class object rather than a field, and the type: ignore is what let it through review — mypy had it right.

Consequence

ListField.unpack's schema branch calls self._item_type(packet) to build a configured per-item field (see #433, which corrected a related bug on that line). Calling a Schema class with a packet dict does not produce a field; it attempts to construct a schema instance from a dict positionally. Depending on the branch taken, this either raises or silently mis-parses.

Why this was unreachable until now

It sits behind the nested-packet fault in #445: the SETTINGS frame's pack path died earlier with KeyError: 'length'. PR #457 fixes #445, and this becomes reachable — the agent implementing it reported SETTINGS as one of five HTTP/2 frames that then fail on distinct, previously-unreachable defects.

Fix

Wrap it as the siblings do:

item_type=SchemaField(schema=SettingPair),

and remove the # type: ignore[arg-type], confirming with mypy rather than assuming — the baseline is 128 errors in 41 files. A regression test should exercise a real SETTINGS frame round trip rather than a fake, since a fake with a compatible __call__ would hide the distinction.

Provenance

Surfaced by the agent implementing #445 (PR #457) and verified independently before filing. Related: #433 (the same ListField schema branch), and #445 which currently masks this.

Activity

  1. JarryShaw commented on Sep 18, 2026

    @JarryShaw
    OwnerAuthor

    Correction to this issue's text: the masking symptom is KeyError: 'flags', not KeyError: 'length'.

    I wrote that the SETTINGS pack path "dies earlier with KeyError: 'length'". That is wrong, and PR #462's reviewer caught it. Reproduced on 0283a6d59:

    proto = object.__new__(HTTPv2)
    schema = proto.make(type=Frame.SETTINGS, sid=0,
                        frame={'settings': [(Setting.HEADER_TABLE_SIZE, 4096)]})
    bytes(schema)
    File ".../pcapkit/protocols/schema/application/httpv2.py", line 144, in post_process
        if packet['flags'][name]:
    KeyError: 'flags'
    

    So the field that cannot be reached is flags, not length, and the raising site is FrameType.post_process at httpv2.py:144 rather than a length callback. 'length' was carried over from #445's CGA Parameters symptom, which genuinely is KeyError: 'length' on a different field in a different module — I reused the phrasing without re-checking what SETTINGS actually raises.

    The substance of this issue is unaffected, and worth restating so the correction is not read as a retraction:

    Noting for whoever picks this up: the same wrong symptom propagated into PR #462's test docstring and description, and its reviewer has flagged it there too.

  2. added a commit that references this issue on Sep 18, 2026
  3. added
    bugIssues reporting a defect (set by the bug report template; a default, not an assessment)
    on Sep 22, 2026
  4. added this to the 1.5 milestone on Oct 6, 2026
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

    bugIssues reporting a defect (set by the bug report template; a default, not an assessment)

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions