Type Object Is Not Subscriptable | Fix It In Minutes

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 like or 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, or typing types like List and Dict.

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 PascalCase and data in snake_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] over typing.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 items or mapping.
  • 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], and tuple[int, ...] when your Python version allows it.
  • Import From typing Only When Needed — Use from typing import Optional and 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(...), not MyClass[...].
  • 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] with MyClass(x) when x is 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'] for Thing.field when 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 PascalCase and runtime values in snake_case.
  • Avoid Shadowing Built-Ins — Skip names like list, dict, set, type, and id for 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 value and type(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.