Repository navigation
1.17.0 regression: dict literals incompatible with Sequence[TypedDict] #19483
Description
Bug Report
(yes I used claude code to sum the issue up)
Summary
mypy 1.17.0 incorrectly reports type errors when using dict literals that should be compatible with Sequence[TypedDict] fields. This worked correctly in mypy 1.16.1 and represents a regression in TypedDict structural typing.
Expected Behavior
Dict literals with the correct structure should be accepted when assigned to fields expecting Sequence[TypedDict], following structural typing principles that TypedDict is supposed to provide.
Actual Behavior
mypy 1.17.0 reports:
error: Incompatible types (expression has type "list[dict[str, str]]", TypedDict item "inputs" has type "Sequence[Component]") [typeddict-item]
Environment
- mypy version: 1.17.0 (fails) vs 1.16.1 (works)
- Python version: 3.11.9
- Platform: Linux
- Dependencies: None (pure
typingmodule)
Minimal Reproducible Example
Save as test_regression.py:
class Component(TypedDict):
"""Simulates ABIComponent from eth_typing"""
type: str
name: NotRequired[str]
components: NotRequired[Sequence['Component']]
class Function(TypedDict):
"""Simulates ABIFunction from eth_typing"""
type: Literal['function']
name: str
stateMutability: Literal['pure', 'view', 'nonpayable', 'payable']
inputs: NotRequired[Sequence[Component]]
outputs: NotRequired[Sequence[Component]]
# This should work according to TypedDict structural typing rules
# Works in mypy 1.16.1, fails in mypy 1.17.0
# Simple case
simple_function: Function = {
'type': 'function',
'name': 'test',
'stateMutability': 'view',
'inputs': [{'type': 'uint256', 'name': 'value'}], # Error in 1.17.0
'outputs': [{'type': 'bool'}] # Error in 1.17.0
}
# Nested case (components within components)
complex_function: Function = {
'type': 'function',
'name': 'complex',
'stateMutability': 'view',
'inputs': [
{'type': 'tuple', 'components': [ # Error in 1.17.0
{'type': 'uint256', 'name': 'amount'},
{'type': 'address', 'name': 'recipient'}
]}
]
}
# Direct assignment to Sequence should also fail
components_list: Sequence[Component] = [
{'type': 'uint256', 'name': 'value'}, # Error in 1.17.0
{'type': 'address'} # Error in 1.17.0
]
# List of functions
function_list: list[Function] = [
{
'type': 'function',
'name': 'func1',
'stateMutability': 'pure',
'inputs': [{'type': 'uint256'}] # Error in 1.17.0
}
]Steps to Reproduce
- Save the code above as
test_regression.py - Run with mypy 1.16.1:
mypy test_regression.py→ ✅ Success - Run with mypy 1.17.0:
mypy test_regression.py→ ❌ Fails
Error Output (mypy 1.17.0)
standalone_bug_test.py:43: error: Incompatible types (expression has type "list[dict[str, str]]", TypedDict item "components" has type "Sequence[Component]") [typeddict-item]
standalone_bug_test.py:62: error: Incompatible types (expression has type "list[dict[str, str]]", TypedDict item "inputs" has type "Sequence[Component]") [typeddict-item]
Analysis
This is a clear regression where mypy 1.17.0 is no longer properly recognizing dict literals as structurally compatible with TypedDict types when used in Sequence[TypedDict] contexts. The fundamental principle of TypedDict structural typing is broken.
Root Cause
The issue appears to be in mypy's type inference logic where:
- Dict literals inside lists are inferred as
dict[str, str]instead of the contextually expected TypedDict - This inference happens before structural compatibility is checked
- The resulting
list[dict[str, str]]is then (correctly) rejected as incompatible withSequence[TypedDict]
Expected Fix
Dict literals should be contextually typed when the expected type is Sequence[TypedDict], allowing structural compatibility to work as intended.
Workarounds
- Use
# type: ignore[typeddict-item]or# type: ignore[assignment]comments - Use explicit
cast(list[Component], [...]) - Use explicit TypedDict construction:
Component(type='uint256', name='value') - Downgrade to mypy 1.16.1
Activity
Bumped ruff to 0.12.4
Bumped ruff to 0.12.4
hauntsaninja commentedon Jul 20, 2025
Hmm, I only see one new error, not four, in your example.
Smaller repro:
Bisects to #19147 , but that PR should mostly only be exposing behaviour latent in mypy
LefterisJP commentedon Jul 21, 2025
Hey you are right. My bad on number of errors. I pasted a different test I had made than the one in the output. I edited it now with one having 2 errors with mypy 1.17.
But I think the bug must be more specific than what I originally thought. Seems like dict literals are not recognized as valid TypedDict instances when used inside a Sequence for recursive/self-referential TypedDict types?
Taking your more minimal repro that seems to be the case? I am really not familiar with the internals of mypy, so can just point to what I see when using it.
Can I provide another example to help you or is the error clear?
sterliakov commentedon Jul 21, 2025
Okay, I probably know the root cause, but let's see the primer first to learn whether this fix is positive enough.
As an aside, please verify the text that some LLM has hallucinated for you before publishing it - use of tools, AI or not, is not a good reason to post unverified and misleading snippets.
LefterisJP commentedon Jul 21, 2025
Thank you guys for the quick reaction. I appreciate it.
Retain `None` as constraints bottom if no bottoms were provided (pyth…
asottile-sentry commentedon Jul 22, 2025
nice! I was about to report a duplicate and noticed this fixed it on a bisect -- here's my minimal reproduction:
perhaps a 1.17.1 ?
hauntsaninja commentedon Jul 27, 2025
Yeah, worth adding to a 1.17.1
Retain `None` as constraints bottom if no bottoms were provided (#19485)
hauntsaninja commentedon Jul 31, 2025
Released!