The error type object is not subscriptable appears when code indexes a class or type; swap in an instance or the right typing form.
You press Run, the script starts, then Python stops with a message that feels oddly personal. This error is common because it often comes from a single pair of brackets in the wrong spot, or a name that points at a class when you thought it pointed at data.
The upside is simple. Once you know what Python means by “type” in that line, you can fix the root cause fast and keep the same logic.
What This Error Means In Plain Terms
Python uses the word type in the error to mean “a class object.” A class is a recipe. An instance is the thing you made from the recipe. Lists, tuples, strings, dicts, and many other values can be indexed with square brackets. Most classes can’t.
So the message is telling you this: the thing on the left side of [...] is a class (or another non-indexable type object), not a container value.
Two Tiny Lines That Show The Difference
class Box:
pass
Box[0] # boom: class used like a list
Box()[0] # different boom: instance still lacks __getitem__
The first line fails because Box is a class. The second line may still fail because the instance does not implement indexing. That split matters, because it tells you which fix path fits your code.
Fast Checks To Find The Real Cause
When this error pops, you want to confirm what the name actually points at in that moment. That sounds abstract, but it’s quick with two checks.
- Print The Value — Add
print(name)right before the failing line to see whether it prints likeor like real data. - Print The Type — Add
print(type(name), getattr(name, '__class__', None))to spot whether the name is already a class, or an instance of one. - Search For Reassignment — Use your editor’s “find all references” on the name and look for a line that reuses it for a class, import, or function.
- Check The Brackets — Scan the exact line for a stray
[]after a class name, a module name, ortypingtypes likeListandDict.
Quick Check That Saves Time
If you can run a REPL, do this on the failing name:
print(name)
print(type(name))
print(hasattr(name, '__getitem__'))
If the first print shows a class, the name points at a type object. If the third line prints False, the value can’t be indexed even if it is an instance.
Fixing Type Object Is Not Subscriptable In Python Code
This section lists the most common patterns that trigger the crash, plus the fix that matches each pattern. Start with the one that looks closest to your line.
Using A Class Where You Meant An Instance
This happens a lot with models, dataclasses, and “manager” style classes. You meant to build an object, but you kept the class name and indexed it.
- Create The Instance — Call the class first, then index the value you stored inside the instance.
- Store Data In A Container — If you want bracket access, place the data in a list or dict attribute.
class User:
def __init__(self, roles):
self.roles = roles
# wrong
User['admin']
# right
u = User({'admin': True})
print(u.roles['admin'])
Indexing A Class When You Wanted A Dict
Sometimes a variable name shadows what you intended. A common case: you import a class named Config, then later you try to use it like a dict.
- Rename The Class Import — Alias the import so it can’t be confused with a config mapping.
- Rename The Data Variable — Keep class names in
PascalCaseand data insnake_case.
from settings import Config as ConfigClass
config = {'mode': 'dev'}
print(config['mode'])
Mixing Up Generics And Instances
If you are using type hints, you might see this error when a typing form is treated like a runtime container. Type hints describe shapes for tools and editors. They are not lists or dicts you can index at runtime.
- Separate Hints From Values — Keep annotations on the left of
=, and real values on the right. - Use Built-In Generics — In modern Python, prefer
list[int]overtyping.List[int]for hints.
# hint
ages: list[int] = [21, 34, 55]
# value indexing
print(ages[0])
When The Built-In Name Got Shadowed
One sneaky source: naming a variable list, dict, or type. Your code still runs until you try to use the built-in later. Then you end up indexing a class or function you did not mean to touch.
- Rename The Variable — Pick a name that describes the data, like
itemsormapping. - Restart The Runtime — In notebooks, rerun from a clean state after renaming so old bindings vanish.
list = int
# later...
list[0] # boom
# fix
items = [1, 2, 3]
print(items[0])
Common Triggers And The Matching Fix
If you want a fast scan, use this table. It maps what you see in code to what is most likely happening under the hood, then the smallest change that usually stops the crash.
| What You Wrote | What It Actually Is | What To Change |
|---|---|---|
MyClass[0] |
A class object | Instantiate or index stored data |
typing.List[int] at runtime |
A typing form | Use a real list value |
Model['id'] |
A model class | Use an instance or a dict |
list[0] after list = Something |
Shadowed built-in | Rename and restart |
EnumType['X'] |
Enum class | Use EnumType.X or EnumType['X'] only when Enum allows it |
Reading The Table Without Guesswork
Check the second column first. If it says “class object,” your fix is about instantiation, naming, or selecting the right attribute. If it says “typing form,” your fix is about separating annotations from runtime values.
Typing, Python Versions, And Bracket Rules
A lot of modern code uses square brackets in type hints. That’s great for readability, but it can blur the line between “types for tooling” and “values for runtime.”
Built-In Generics Versus typing.*
Python 3.9 added bracket syntax on built-in containers, so you can write list[str] and dict[str, int] in annotations. Older codebases often used typing.List and friends.
- Use Built-In Brackets In Annotations — Prefer
list[int],dict[str, int], andtuple[int, ...]when your Python version allows it. - Import From typing Only When Needed — Use
from typing import Optionaland other helpers when there is no built-in form that fits.
Custom Classes And Square Brackets
Some libraries allow bracket syntax on classes. They do that by defining special methods that Python checks when it sees MyClass[Something]. If your class lacks that hook, you get this error.
- Use Parentheses For Construction — If you meant to build an object, call
MyClass(...), notMyClass[...]. - Add A Bracket Hook Only When Needed — If you are building a generic-like API, use the
__class_getitem__for class-level brackets.
class Cache:
def __class_getitem__(cls, item):
return (cls, item)
print(Cache[int])
This pattern is niche. Most apps should not add it just to silence an error. If you only need runtime indexing, you want __getitem__ on an instance.
Fix Patterns You Can Apply Right Away
The fastest fixes tend to fall into a few repeatable edits. These are the ones that solve most cases without changing your wider design.
Switch Brackets To Parentheses
If the left side is a class name, and the inside of the brackets looks like constructor input, this is almost always the right move.
- Call The Class — Replace
MyClass[x]withMyClass(x)whenxis meant as init data. - Move Indexing After Construction — Build the instance first, then index a container attribute.
Replace Class Indexing With Attribute Access
In enums, dataclasses, and ORMs, the class often holds descriptors, not data. If you are trying to reach a field, you may want dot access instead of indexing.
- Use Dot Syntax — Swap
Thing['field']forThing.fieldwhen the API is attribute-based. - Read The Library Pattern — Skim the project docs or autocomplete hints to see whether the object uses attributes, dicts, or methods.
Turn The Instance Into A Container
If you want obj['x'] on your own classes, you can add __getitem__. That makes the instance indexable, which can be handy for wrapper types.
- Add __getitem__ — Return the item from an internal dict or list.
- Keep The Internal Store Obvious — Name it clearly so readers know where data lives.
class Bag:
def __init__(self):
self._data = {}
def __getitem__(self, k):
return self._data[k]
def __setitem__(self, k, v):
self._data[k] = v
b = Bag()
b['x'] = 3
print(b['x'])
Habits That Keep It From Coming Back
This error loves messy naming and mixed roles. A few simple habits cut the odds of seeing it again, especially in notebooks and larger codebases.
- Use Clear Naming Conventions — Keep class names in
PascalCaseand runtime values insnake_case. - Avoid Shadowing Built-Ins — Skip names like
list,dict,set,type, andidfor your own variables. - Restart After Refactors — In interactive sessions, a restart clears stale bindings that can keep pointing at an old class.
- Keep Type Hints On The Left — Treat annotations as metadata, not containers to index at runtime.
- Add Small Assertions — A quick
assert not isinstance(name, type)near critical paths can catch a bad assignment early.
When A Library Triggers The Crash
Sometimes the traceback points into a third-party package. That does not mean the package is broken. Most of the time you handed it a class object where it expected a real value, then the package tried to index it.
Use the lowest frame in the traceback that still sits in your code. That is where your inputs enter the library. Check the variables you pass, then print them right before the call.
- Read The Traceback From The Bottom — The last call in your file usually shows the exact expression that used brackets.
- Print The Value And Type — Log
valueandtype(value)so you can spot a class object in one glance. - Check Imports And Aliases — A wrong import can replace a function with a class that has the same name.
If the package uses square brackets for its API, double-check you are not feeding it a class. Print the argument right before the call. If it ends with , you found the culprit right there.
When you see this error again, read it as written. Python is telling you the thing you indexed is a type. Once you confirm which name became that type, the fix is one edit.
If you are scanning logs and you spot the phrase type object is not subscriptable, jump straight to the failing brackets and print the value one line above. That single check often ends the hunt.
