
This TypeError type object not subscriptable is common if you are learning modern Python but running code on an older server or Environment (like Python 3.8 or older).
It happens when you try to use Type Hinting generics with standard types.
⚡ Quick Fix: TypeError: ‘type’ object is not subscriptable – Python 3.8 Type Hint Generic Syntax and typing Module Fix
You used list[str] or dict[str, int] syntax on Python 3.8 or older — that generic bracket notation only works on Python 3.9 and above.
# Fix 1 — Python 3.9+: use built-in types directly with brackets
def my_func(x: list[str]) -> dict[str, int]:
pass
# Fix 2 — Python 3.8 and below: import capital-letter types from typing
from typing import List, Dict, Tuple, Optional
def my_func(x: List[str]) -> Dict[str, int]:
pass
my_var: List[int] = [1, 2, 3]
# Fix 3 — All versions: use from __future__ import annotations to defer evaluation
from __future__ import annotations
def my_func(x: list[str]) -> dict[str, int]: # Works on 3.7+
passThis tells you exactly where your boundary is — Now read through the root causes below to find which one broke your code and fix it permanently.
The Cause
In Python 3.9+, you can write:
# "x is a list of strings"
def my_func(x: list[str]):
passHere, list is a “type object.” In older Python, types couldn’t be “subscripted” (put in brackets []).
Problem Code (Run on Python 3.8):
my_var: list[int] = [1, 2, 3] # CRASH! TypeError: 'type' object is not subscriptable
Fix 1: Upgrade Python (Best)
If possible, upgrade your environment to Python 3.9 or newer. This syntax is the modern standard.
Fix 2: Use the typing Module (Legacy Support)
If you are stuck on an older version (like in some AWS Lambda environments), you must import the capital-letter versions from typing.
from typing import List, Dict, Tuple
# Use List (capital L), not list
def my_func(x: List[str]):
pass
my_var: List[int] = [1, 2, 3]This works on all versions of Python 3.
What This Error Exposes About Python’s Type System Evolution
TypeError: 'type' object is not subscriptable is Python’s built-in type objects refusing a bracket operation they did not support before Python 3.9. In Python 3.8 and earlier, list, dict, tuple, and set are plain type objects with no __class_getitem__ method — the hook that enables list[str] syntax. Writing list[str] calls list.__class_getitem__(str), which raises TypeError on any version that never implemented that method. The typing module provides List, Dict, and Tuple to fill this gap. These generic alias wrappers implement __class_getitem__ across all Python 3 versions.
The from __future__ import annotations fix operates on a different mechanism entirely. This switches annotation evaluation from eager to lazy. Type hints become raw strings at definition time. The interpreter never evaluates them during execution. Therefore, list[str] in a signature never triggers __class_getitem__ on Python 3.7 and 3.8. The bracket expression simply remains unexecuted. This is the cleanest compatibility fix for modern annotation syntax without Python 3.9. Plus, it costs nothing at runtime.
The version targeting decision matters most in deployment environments you do not control. Environments like AWS Lambda and Google Cloud Functions run pinned Python versions. These often lag behind the current release. A codebase written locally on Python 3.11 may deploy to a Python 3.8 Lambda function. This causes import crashes on files using bare generic syntax. The safest policy is to add from __future__ import annotations to files using type hints. Use typing module imports as a fallback. This covers tools like mypy or linters that lack deferred evaluation support.





