Function Object Is Not Subscriptable | Fix It Fast

The “function object is not subscriptable” error means you used square brackets on a function instead of calling it or indexing the value it returns.

You’ll usually hit this in Python when you treat a function like a list, dict, or DataFrame. The code runs until it reaches the brackets, then Python stops and throws the TypeError. The fix is often one character: swap [] for (), or call the function first, then index the result.

This guide walks through the common causes, how to spot the exact line that triggered it, and the cleanest fixes you can reuse. It’s written so you can scan, make the change, and move on.

Why This Error Pops Up

In Python, square brackets mean “get an item from this object.” Lists, tuples, strings, dicts, and many library objects implement that behavior. Functions don’t. A function is a callable object: you run it with parentheses, and it produces a return value.

So when Python sees something like my_func[0], it tries to subscript the function object itself. Since functions don’t define item access, Python raises a TypeError.

  • Indexing A Function Name — You wrote thing[0] but thing is a function, not the value you meant to index.
  • Forgetting Parentheses — You meant thing() but typed thing, then indexed it later.
  • Overwriting A Variable — A name that used to be a list or dict got reassigned to a function.
  • Shadowing A Built-In — You named a function list, dict, or sum, then tried to use the built-in later.

Function Object Is Not Subscriptable In Python Code

The fastest way to win against this error is to read it like a map. Python tells you two things: the type it couldn’t subscript, and the line where it happened. Start with the stack trace, jump to the bottom line that points into your file, and zero in on the expression right before the brackets.

What You Wrote What Python Thinks It Is Fix That Works
get_user[0] get_user is a function Call it: get_user()[0]
config["mode"] config is a function Rename the function or call it: config()["mode"]
data["col"] data is a method reference Add parentheses: data()["col"]
df["age"] df got reassigned Find the reassignment and undo it

If you see this message during debugging, it’s worth saying it out loud: “I’m indexing the function, not its result.” That one sentence tends to point your eyes to the missing parentheses or the wrong name.

Read The Traceback Without Guesswork

A traceback can look noisy, yet it’s the shortest path to the fix. Start at the last line of the traceback. That line shows the file, line number, and the expression that raised the TypeError. The earlier lines show how your code got there.

If the traceback points into a library file, don’t panic. Scroll up until you find the last frame that lives in your codebase. That’s the call site you control, and it’s usually where the wrong object got passed in.

  • Jump To The Bottom Frame — The final line is where Python stopped; copy that line number into your editor.
  • Circle The Brackets — Find the [] that triggered the error, then read the name immediately to the left.
  • Trace The Name Back — Follow that name to where it was assigned so you can see when it became a function.
  • Confirm The Runtime Type — Print type(name) right before indexing to verify what you’re holding in that moment.

Callable Vs Subscriptable In Plain Terms

Two built-ins help you think clearly here. callable(x) tells you whether Python can run x(). Subscriptable objects implement item access, which is why x[0] works on lists and strings. You can check that behavior by testing hasattr(x, "__getitem__").

It’s normal for an object to be one but not the other. Functions are callable and not subscriptable. Lists are subscriptable and not callable. Some objects are both, like certain callable classes that also expose items. When you know which side you need, the syntax becomes obvious.

One-Liners That Reveal The Bug

When the failing expression is long, shrink it. Assign each piece to a name, then print the type after each step. This keeps you from guessing.

  • Split The Expression — Turn get_data()[0]["id"] into two lines so you can print after each operation.
  • Inspect The Return Value — Call the function once, store it, then check what you can index or slice on it.
  • Check The Name Collision — If data is both a function and a variable in different files, rename one to stop accidental reuse.

Quick Checks That Catch It In Seconds

Before you refactor anything, run a few checks at the place that fails. They’ll tell you what your variable name points to at runtime, not what you meant it to be.

  • Print The Type — Add print(type(x)) right before the failing line to see whether x is a function.
  • Print The Value — Add print(x); functions show up like or .
  • Check For Parentheses — If you expected a dict, list, or DataFrame, ask yourself where () should be.
  • Search For Reassignment — Use your editor search for x = to spot where the name changed type.

When you’re in a notebook, a quick sanity check is x? in IPython. It shows whether you’re holding a callable or a concrete value.

Fixing A Function Object Not Subscriptable Error Cleanly

Most fixes fall into a few patterns. Once you recognize the pattern, you can patch it quickly and keep the code readable.

Call The Function, Then Index The Return Value

This is the classic case. You meant to grab an item from the data produced by a function, not from the function itself.

  • Use Parentheses First — Change users[0] to users()[0] if users is a function that returns a list.
  • Store The Result — Assign u = users(), then use u[0] so the call and the indexing are easy to read.

Index A Method Result, Not The Method Reference

Bound methods can look like values in code completion, so it’s easy to forget the call. The giveaway is seeing something like when you print the object.

  • Add The Missing Call — Turn obj.get["x"] into obj.get()["x"] if get returns a dict.
  • Pick The Right Attribute — If a library offers both a property and a method with similar names, use the one that returns the data you need.

Stop Overwriting Data Names With Functions

This happens when you reuse a short name like data for two different roles. The code works early in the script, then breaks later after the reassignment.

  • Rename One Of The Two — Use get_data for the function and data for the returned value.
  • Keep Data And Callables Separate — Adopt a naming habit: verbs for callables, nouns for values.

Undo Shadowing Of Built-Ins

Shadowing is when you assign to a name that Python already uses. It doesn’t crash right away, so it can feel random when the failure appears later.

  • Rename Your Function — If you wrote list = ... or def list(...), rename it to something specific like items_list.
  • Restart The Runtime — In notebooks, old bindings stick around. Restarting clears the shadowed name.

Common Situations In Real Projects

You’ll see the same root mistake across different libraries. Once you know what the error means, you can spot it even in code you didn’t write.

Pandas And DataFrames

Pandas uses brackets a lot, so this one shows up often. A frequent trigger is assigning a DataFrame-building function to the same name you later treat like a DataFrame.

  • Check The DataFrame Name — If df["col"] fails, print df. If it prints like a function, find where df was set.
  • Call Factory Functions — If you wrote df = build_df, change it to df = build_df().

Flask, Django, And Web Handlers

Web libraries often use decorators, which can blur the line between a function and the value it returns. If you decorate a function and then try to treat that name like a dict, you can trip this TypeError.

  • Separate Handler And Data — Keep get_settings() as the callable and store its result in settings.
  • Check What The Decorator Returns — Some decorators replace your function with another callable. Print the name to see what you’re holding.

NumPy And Callables That Produce Arrays

NumPy makes it easy to think in arrays. If a helper returns an array, you must call it before slicing.

  • Call Then Slice — Change make_array[:10] to make_array()[:10].
  • Freeze The Output — Store a = make_array() once, then slice a many times.

Habits That Stop This From Coming Back

This error is simple, yet it can waste time when it shows up in the middle of a bigger task. A few habits keep it rare.

  • Use Descriptive Names — Names like get_users and users make it obvious which one needs parentheses.
  • Lean On Type Hints — Even basic annotations help editors flag when you index a callable.
  • Add Assertions In Debug Builds — A quick assert not callable(x) before indexing can catch bad reassignments early.
  • Write Small Tests For Helpers — If a helper should return a dict, test that return type once, then trust it.

Your editor can catch a lot of these before you run the file. If you use VS Code, PyCharm, or another IDE, turn on type checking and linting for the project. Even light settings can flag “indexing a callable” when it sees [] on a name annotated as a function.

  • Run A Type Checker — Tools like mypy can warn when a function is used like a dict or list. It’s a small habit that saves minutes daily.
  • Enable Lint Rules — Linters like ruff or pylint can spot shadowed built-ins and risky reassignments.
  • Use Auto-Rename — If you rename a function, let the editor rename all references so you don’t leave old names behind.

If you’re still stuck, reduce the failing line to a tiny snippet. Print the object, call it, print the return type, then index. This stepwise check usually reveals where the type changed.

When you see this TypeError again, remember the core rule: square brackets are for values that hold items. Parentheses are for functions that produce those values. That’s the whole game, and it’s why function object is not subscriptable is one of the quickest Python errors to fix once you know what to look for.

One last check: if the error message reads function object is not subscriptable but you swear you used parentheses, scan for a name collision. A helper function and a variable sharing the same name can make the code look right while still indexing a callable.