TypeError: `’type’` Object Is Not Subscriptable
TypeError: 'type' object is not subscriptable means Python found a class or type object immediately before [] when your code expected an indexable value; Python 3.8 or earlier also raises it for built-in generic annotations such as list[str]. Brackets work with values that support indexing or key lookup, including lists, strings, tuples, dictionaries, and some library objects, not with most class definitions. The fix is to identify what is to the left of [], then use an instance, call a function, or change older type-annotation syntax.
Use this table to match the failing line to the likely correction.
| Symptom | Likely Cause | Fix |
|---|---|---|
Check whether items is a type object rather than a list instance before indexing it. |
items refers to the list class, not a list value |
Create or assign a list instance, such as items = [] or items = ["a"] |
DataFrame["name"] raises the error |
You used the DataFrame class name instead of a DataFrame instance |
Construct or obtain an instance, then index that instance |
list[str], dict[str, int], or type[User] fails on Python 3.8 or earlier |
That interpreter does not support built-in generic syntax | Use the matching types from typing, such as List[str] |
load_records[0] raises a function-object error |
You indexed the function itself instead of its return value | Call it first: load_records()[0] if it returns an indexable value |
A GroupedData or TargetEncoder object is not subscriptable |
The library object does not implement [] access |
Use the library’s documented method or transform that produces the data you need |
What the Error Means
“Subscriptable” is Python’s term for an object that can appear on the left side of brackets:
names = ["Ada", "Grace"]
first_name = names[0]
Here, names is a list instance, and lists support integer indexes.
names = list
print(type(names))
print(names[0])
names is now the built-in list class, not a list containing values. Python may report its type as type; if it does not support indexing, names[0] raises this error.
The distinction is small but important:
items = list # The list class
items = list() # An empty list instance
items = [] # An empty list instance
The second and third lines create values that can be indexed after they contain elements. The first line assigns the class object itself.
Read the expression immediately to the left of [] before changing the line that raised the error. That tells you whether you accidentally used a class, forgot to call a function, or used annotation syntax unsupported by the interpreter.
How to Fix the TypeError
Step 1: Find the Exact Bracket Expression
- Read the last line of the traceback. It identifies the statement that attempted subscription.
- Locate the expression directly before
[on that line. - Print the value and its type if the cause is not obvious.
For example, if the traceback points to purchase[0], temporarily inspect purchase:
print(repr(purchase))
print(type(purchase))
print(isinstance(purchase, type))
If the output includes something like <class 'list'>, <class 'MyClass'>, or True from isinstance(..., type), you are holding a class object rather than the data you intended to index.
If the failing code contains type hints such as list[str], check the interpreter that runs the file, test suite, notebook kernel, or deployment environment:
python --version
A project can work locally but fail in CI, a container, or a notebook if those environments use different Python versions.
Step 2: Match the Fix to What the Brackets Were Meant to Do
There are three common intentions behind [].
- You meant to index a collection. Replace the class reference with a collection instance or the variable that holds one. Incorrect:
purchase = list brand = purchase[0]Correct:
purchase = ["SteelSeries", "Rival 600", 69.99] brand = purchase[0] - You meant to use the result of a function. Call the function before indexing its return value, but only when the function returns a list, tuple, string, dictionary, or another indexable object. Incorrect:
first_record = load_records[0]Correct:
first_record = load_records()[0] - You meant to write a type annotation. On Python 3.8 or earlier, replace built-in generic syntax with imports from
typing. For a list of dictionaries and a two-string tuple return value, writeList[Dict]andTuple[str, str].from typing import Dict, List, Tuple def run_node(input_data: List[Dict]) -> Tuple[str, str]: return "", ""For a class object constrained to a particular base class, use
Type[User]rather thantype[User]on those older interpreters.
Step 3: Run the Smallest Useful Check
After changing the code, rerun the smallest command, test, or import that originally failed.
For an indexing mistake, verify that the variable now contains the kind of value you expect. For example, a list should display with square brackets, while a class usually displays as <class '...'>.
For a function-call mistake, confirm that the function returns a value that supports indexing. Calling the function may expose a different error, such as a missing return value or an empty list. That is useful progress: it means the original type-object problem is fixed and Python has reached the next real condition in the code.
For an annotation issue, import the module or run the test suite using the same interpreter that failed before. Do not confirm the fix only in a newer local interpreter if the application will run elsewhere.
Fixing Generic Type Annotations on Older Python
Built-in generic syntax is available in Python 3.9 and newer:
def format_names(names: list[str]) -> dict[str, int]:
return {name: len(name) for name in names}
On an older interpreter, Python evaluates list[str] while defining the function. Since that version’s list type cannot be subscripted for generic annotations, module import or function definition fails before your program reaches its main logic.
Use equivalents from typing instead:
from typing import Dict, List, Tuple
def run_node(input_data: List[Dict]) -> Tuple[str, str]:
return "", ""
The same conversion applies to other common annotations:
| Newer Built-In Syntax | Older-Compatible Annotation |
|---|---|
list[str] |
List[str] |
dict[str, int] |
Dict[str, int] |
tuple[str, str] |
Tuple[str, str] |
type[User] |
Type[User] |
Import only the names your module uses:
from typing import Type
def create_user(model: Type[User]) -> User:
return model()
This issue is about annotation syntax, not the behavior of your data. Changing list[str] to List[str] does not convert anything at runtime; it makes the annotation valid for the interpreter running the code.
Common Code Patterns That Cause the Error
The following patterns show how classes, built-in types, functions, helper objects, and fixture results can end up to the left of [] instead of indexable data.
Using a Class Name Instead of an Instance
Classes are commonly written in PascalCase, such as User, Order, or DataFrame. Instances are commonly stored in lowercase variables, such as user, order, or frame.
This fails because DataFrame is a class:
column = DataFrame["name"]
This can work when frame is an instance from a library that supports column access:
frame = DataFrame(data)
column = frame["name"]
The same distinction applies to your own classes. User[0] is not a way to get the first user unless your class deliberately implements class-level subscription. Usually, you need a collection such as users[0].
Assigning a Built-In Type by Accident
When you intend to initialize containers, these assignments instead create references to built-in classes:
records = list
settings = dict
labels = tuple
They are easy to write when you intend to initialize a container. Use an instance instead:
records = []
settings = {}
labels = ()
If you need to convert existing data, call the type:
records = list(source_records)
Indexing a Function Rather Than Its Result
A function name is an object, but it is not normally a collection:
def get_statuses():
return ["queued", "running"]
status = get_statuses[0]
Call the function first:
status = get_statuses()[0]
Be careful not to add parentheses automatically to every failing expression. A class, property, or library object may need a different correction. The goal is to make the left side of [] the actual value you want to query.
Treating Library Helper Objects Like Data Containers
Some APIs return helper objects that represent an operation rather than data you can index. Library helper objects can produce a similar error when they do not support bracket access.
These errors are closely related but may not say 'type' object; they often name the object’s class instead. The meaning is still the same: the object does not define bracket access. Use the library operation intended to aggregate, transform, encode, or retrieve results, then index the resulting list, mapping, table, or array only if that returned value supports it.
Returning a Class From a Fixture or Factory
In test code, it is possible to return a class object when a test expects sample data or an initialized object:
@pytest.fixture
def records():
return Record
A later records[0] then fails because records is the Record class.
Return an instance or a collection of instances when that is what the test consumes:
@pytest.fixture
def records():
return [Record()]
This also explains many errors that mention a DataFrame type in pytest: the fixture, mock, or patch may have supplied the class rather than a populated DataFrame instance.
Confirm the Fix and Avoid Repeating It
Before considering the issue closed, check these points:
- The expression before
[]is a real runtime value, not a class name. - A function is called with
()before you index the value it returns. - A fixture, factory, or dependency injection setup returns the expected instance or collection.
- Type annotations match the Python interpreter used in tests, containers, notebooks, and production.
- The original failing test or script now reaches its expected result.
Use descriptive variable names to make class-versus-instance mistakes easier to spot. User and users communicate different things; user_class and user make the distinction even clearer where both are needed.
If the same project supports multiple Python versions, keep its annotations compatible with the oldest interpreter it must run. Otherwise, set and enforce one interpreter version across local development, automated tests, and deployment.
Frequently Asked Questions
What Does TypeError: 'function' Object Is Not Subscriptable Mean?
It means you placed [] after a function object instead of after a value returned by that function. If get_items returns a list, use get_items()[0] rather than get_items[0]. If it returns None, a generator, or a custom object, inspect that return value before deciding how to access it.
Why Does Pytest Say Type DataFrame Is Not Subscriptable?
In pytest, it usually means a test, fixture, mock, or patch passed the DataFrame class where the test expected a DataFrame instance. Use the variable holding the constructed DataFrame, such as frame["column"], rather than the class name DataFrame["column"]. Also inspect fixture return values when the failing expression is several calls away from the fixture definition.
How Do I Fix a GroupedData or TargetEncoder Object That Is Not Subscriptable?
Do not use [] unless that object’s API explicitly supports it. A grouping or encoder object typically represents a pending operation, configuration, or transformation rather than a row, column, or list item. Call the appropriate library method to perform the operation, then work with the returned data structure.
Will Installing Something With pip Fix This Error?
Usually, no. pip installs packages, but it does not change whether your current Python interpreter allows list[str] or whether a class object can be indexed. Fix the expression that uses [], and make sure the interpreter version matches the annotation syntax in the code.
Why Does This Happen in MicroPython?
When this error occurs in MicroPython, test the failing expression in the target environment. A class object still cannot be indexed unless that class supports subscription, and advanced annotation syntax may not be available in the target runtime. Run a minimal reproduction on the actual device or MicroPython environment, then use ordinary runtime values and only the supported annotation features in that codebase.
