AttributeError: ‘Str’ Object Has No Attribute ‘Info’ | Fast Fix

The error AttributeError: ‘str’ object has no attribute ‘info’ appears when Python treats your value as a plain string while you call .info().

Seeing this message pop up in the middle of a script can feel confusing, especially when you expect a pandas DataFrame, a custom object, or a logger. Instead of the object you expect, Python is working with a simple string, so the attribute lookup for info fails.

Most of the time this happens after a quiet change earlier in the code: a helper now returns text, a list stores labels instead of objects, or a formatter turns an object into a readable string. By the time you call .info(), the value still carries a familiar name, yet its type has changed underneath.

This guide walks through what the message means, where it usually comes from, and clear steps you can follow to fix it and avoid the same trap in new code.

AttributeError: ‘Str’ Object Has No Attribute ‘Info’ In Plain Terms

Before touching any code, it helps to decode the message. Attribute access in Python uses the dot syntax. When you write obj.info(), Python looks for a method named info on the object stored in obj. If the object exposes that attribute, the call goes ahead. If not, Python raises an AttributeError.

Strings in Python expose many methods such as upper, lower, and split, but they do not ship with info. So when the interpreter raises AttributeError: ‘Str’ Object Has No Attribute ‘Info’, it is telling you that the actual value stored in that variable is a str, not the richer object you expect.

The difference between a value and its attributes matters here. The value is the thing stored in memory, such as a string or a DataFrame. Attributes are extra pieces that live on that value, such as methods, fields, or properties. A string and a DataFrame might both contain readable data, yet the DataFrame also carries an info method while the string does not.

Here is a tiny sample that reproduces the problem in its simplest form.

text = "hello world"
text.info()

This code fails because text is a str. In real projects the pattern hides behind more layers, which is why this error often feels mysterious at first glance.

Fixing The ‘Str’ Object Has No Attribute Info Error In Python

When you run into this message, you can treat it as a signal that something upstream changed the type of your variable. A short, repeatable checklist helps you track it down without guesswork.

  1. Print The Type First — Run print(type(your_var)) right before the failing line to confirm that it holds .
  2. Search Backward Through Assignments — Scan previous lines and functions to see where that variable was last set or returned.
  3. Check Return Values From Helpers — Make sure any helper function that is supposed to return a DataFrame or custom object actually returns it instead of a string.
  4. Call .info() On The Right Object — Move the .info() call onto the object that actually holds your data, not onto a name, label, or path stored as text.
  5. Rename Ambiguous Variables — Replace names such as table_name or car when they jump between string and object roles inside the same scope.

Once you know where the string slips in, the fix usually turns into a direct change: adjust a return value, pass the correct variable into a function, or swap the target of the .info() call.

At this stage it often helps to read the full traceback from bottom to top. The last line shows the AttributeError, the few lines above it show the call site, and earlier frames point toward helpers and wrappers that may have changed the value along the way.

Step-By-Step Fixes For The ‘Info’ AttributeError

Check Whether You Store Objects Or Their Names

A frequent source of the error is a list or dictionary that holds the names of objects as text instead of the objects themselves. That pattern often appears in small scripts such as menu driven programs or quick demos.

class Transport:
    def info(self):
        print("Transport info")

transport1 = Transport()
transport2 = Transport()
transport3 = Transport()

# Problem: this stores strings, not objects
vehicles = ["transport1", "transport2", "transport3"]

choice = 1
vehicles[choice - 1].info()  # AttributeError here

Here the list stores three strings, so indexing into it returns a str. The solution is to store object references instead.

vehicles = [transport1, transport2, transport3]
vehicles[choice - 1].info()  # Calls Transport.info correctly

The same pattern shows up with dictionaries. A mapping from labels to strings might look tidy, yet if you then expect to call .info() on those entries you will meet the same AttributeError.

vehicles = {
    "slow": "transport1",
    "medium": "transport2",
    "fast": "transport3",
}

vehicles["fast"].info()  # Again, this is a str, not Transport

Replacing those entries with Transport instances keeps both code and mental model aligned.

Watch For Functions That Return Strings Instead Of DataFrames

When you rely on pandas, the .info() method usually belongs on a DataFrame or Series. A helper wrapper around read_sql or another loader can quietly return a string if the signature or call site drifts.

def sql_reading(table_name, comment):
    table = pd.io.sql.read_sql(table_name, con=engine)
    print(comment)
    table.info()
    return table

# Later
orders = sql_reading("orders", "Orders table loaded")
orders.info()  # Works if sql_reading returns a DataFrame

If the wrapper instead returns the original table name or some formatted string, a later call such as orders.info() will fail with the same message. Aligning the return value with the call site resolves the issue.

In longer modules, a helper might move into a new file or gain extra branches, and one branch may now return a message string on error. When a caller does not handle that branch and still calls .info(), the same AttributeError appears while the happy path still returns a DataFrame.

Patterns That Turn Your Object Into A Plain String

Sometimes the code that flips a rich object into text hides in a different module, in a utility function, or inside a loop. Spotting these patterns speeds up debugging.

  • Using __str__ Or f-Strings Too Early — Calling str(obj) or using an f-string to build a message stores only the text form, so later calls to info() will fail.
  • Serialising To JSON Or YAML — Dumping data to a string for logging or network transport and then reusing that string variable later without loading it back into structured form.
  • Mixing Up Labels And Objects In Containers — Lists, tuples, and dicts that sometimes hold names, sometimes hold full objects, which makes it easy to pass the wrong entry into a function.
  • Shadowing Imports With Local Names — Reusing names such as logging, df, or info for strings or other values, which hides the object you actually need.

Another subtle pattern appears when you work with third party APIs. A client library might return a response object with many methods, while a later helper stores only the response.text field. If you then pass that value into code that still expects the full response object, .info() will no longer be available.

Each pattern shares the same root: at some point you replace the object that owns an info method with plain text and then forget that change when writing later lines.

Keeping Types Under Control While You Debug

When a project grows past a single file, keeping track of types in your head turns into guesswork. A couple of simple habits can make these AttributeErrors far less common.

  1. Add Targeted Print Statements — Insert short diagnostics such as print("orders type:", type(orders)) right before the failing call.
  2. Use isinstance Checks For Branches — Before calling .info(), branch on isinstance(obj, pd.DataFrame) or another expected type and log a short warning if the check fails.
  3. Lean On Type Hints — Add type hints to your function signatures so that editors and static checkers can point out mismatched types before runtime.
  4. Step Through With A Debugger — Use breakpoints in your IDE to watch how the value changes line by line until it becomes a string.

These steps strengthen your mental model of the code path and make the next strange AttributeError much easier to track down.

You can also add light logging around main paths. Even a single log line that prints both the variable name and its type near the top of a function gives you a fast pointer when a later call site fails with this error.

Preventing The ‘Info’ AttributeError In New Code

A bit of structure in how you name variables and write helpers keeps this class of bug away from production code. Small choices during design reduce the chance that a string sneaks into a spot that expects a richer object.

  • Use Clear, Stable Naming — Reserve names ending with _name, _label, or _path for text, and names like df_orders for DataFrames.
  • Write Thin Loader Functions — Keep helpers such as load_orders() limited to reading and returning a DataFrame instead of mixing in printing or formatting.
  • Add Small Tests Around Loaders — A tiny test that calls a loader and checks isinstance gives early warning when a refactor changes the returned type.
  • Avoid Reusing Names Across Scopes — Do not reuse the same variable name for both a DataFrame and a string in different parts of the same module.

Team habits matter as well. When code review comments gently nudge new code toward clear naming and stable return types, these AttributeErrors appear far less often in shared branches.

Once you know why AttributeError: ‘Str’ Object Has No Attribute ‘Info’ shows up, you can explain the pattern to teammates and bake simple checks into your templates or project starter files.

Quick Reference Table For ‘.info()’ On Different Objects

The table below summarises where .info() usually makes sense in Python projects and where it triggers AttributeError instead.

Value Type Can You Call .info()? Safer Pattern
Plain string (str) No, raises AttributeError Store and pass the original object that holds the data.
pandas DataFrame or Series Yes, .info() prints column and memory details. Call .info() directly on the DataFrame variable.
Custom class with def info(self) Yes, as long as you keep passing the instance, not its name. Store instances in lists or dicts instead of their string names.
Logger from the logging module info is a method, so call logger.info(...). Keep logger variables distinct from strings that hold messages.

A short comment beside the line that calls .info() can also remind you later which object should own that method.

Keep this mental map nearby while reading stack traces, and the next time you see this message in daily Python work you will know exactly where to look first.