The error means you called sort_values on a None object; confirm you have a real DataFrame and avoid assigning results from in-place calls.
Seeing AttributeError: 'NoneType' object has no attribute 'Sort_Values' can bring a notebook to a halt. In plain terms, Python is telling you that the variable before .sort_values(...) is actually None, not a DataFrame or Series. The fix starts with finding where that None came from, then applying tidy Pandas habits that stop the bug from returning.
What The Error Really Means
Quick check: The error fires when you call a method on a variable that is None. In Pandas, this often happens after a chain that produced no object or when an in-place operation returned None and you captured it by assignment. Python’s AttributeError in this form is common across libraries; the pattern is the same: a method is asked to run on an empty reference.
With Pandas, the two most frequent roots are:
- Assigning the result of an in-place method — Many methods support
inplace=True. When used, they mutate and returnNone. If you writedf = df.sort_values(..., inplace=True), you setdftoNone, and the next call ondfraises the error. The Pandas docs for DataFrame.sort_values showinplace=Falseas the default and demonstrate using the returned DataFrame when not sorting in place. That pattern avoids this trap. - Breaking a chain with a method that returns
None— In Python, several mutating methods returnNoneby design. Assigning their return value or chaining after them turns your variable intoNone. A classic teaching example islst = lst.sort()on a list, which setslsttoNone. The same idea applies to Pandas when you pick in-place paths that do not return an object. See this evergreen pattern in community answers aboutNonereturns and method misuse on Stack Overflow’s “Why do I get AttributeError: ‘NoneType’…” thread.
AttributeError: ‘NoneType’ Object Has No Attribute ‘Sort_Values’ — Common Causes And Fixes
Use the table as a spot guide, then the code that follows to lock in the fix.
| Cause | Typical Symptom | Safe Fix |
|---|---|---|
Assigned result of an in-place call (inplace=True) |
Variable becomes None; next method call fails |
Drop inplace and use the returned DataFrame, or call in place without assignment |
Chained call after a method that returns None |
Chain breaks where None enters the pipeline |
Refactor into pure expressions that return objects |
Upstream step produced None (bad function path) |
Function meant to return a DataFrame returns None |
Add checks; return a real DataFrame on every branch |
Wrong method name or case (typo vs sort_values) |
Attribute not found; sometimes masked by earlier None |
Use sort_values (lowercase) or sort_index where intended |
Fix The Error Step By Step
Work through these steps in order. Each step is short and prevents a class of bugs.
- Print And Assert Early — Right before sorting, add:
print(type(df)) assert df is not None, "df is None before sort_values"If
dfis alreadyNone, the problem sits upstream. - Remove In-Place Assignments — Replace in-place patterns with expression returns:
# Bad: df becomes None df = df.sort_values("col", inplace=True) # Good: use returned object df = df.sort_values("col") # default inplace=False # Also fine: mutate without assignment df.sort_values("col", inplace=True) # then keep using dfThe Pandas reference shows
inplaceis optional and defaults to false; using the return keeps code clearer and safer. - Refactor Broken Chains — Keep every step return a DataFrame:
# Risky if any step returns None df = (load_df() .merge(dim, on="k") .sort_values("score")) # fails if load_df() returned None # Safer split with checks df = load_df() if df is None: raise ValueError("load_df returned None") df = df.merge(dim, on="k").sort_values("score") - Confirm The Correct Method — Use
sort_valuesfor value sorting,sort_indexfor index sorting. The oldsortis gone; guides note the removal and steer to the correct names. See Pandas docs and upgrade notes from community posts. - Return Real DataFrames From Helpers — Ensure utility functions never return
Noneon a normal path:def tidy(df): if df is None or df.empty: # Return an empty DataFrame, not None return pd.DataFrame(columns=["a","b","c"]) return df.assign(ratio=df.a/df.b) - Handle Empty Inputs — An empty DataFrame is valid and still has
sort_values. Code that swaps an empty input forNonewill later explode. Preserve the DataFrame shape or guard the branch:if df is not None and not df.empty: df = df.sort_values("a")
Correct Patterns For Sorting With Pandas
Stick to patterns that read clearly and always return a predictable object. These avoid the pitfall behind AttributeError: ‘NoneType’ object has no attribute ‘Sort_Values’.
- Prefer expression returns — Use the returned DataFrame from
sort_values:df_sorted = df.sort_values(by=["score", "ts"], ascending=[False, True])The official
sort_valuessignature and options are in the Pandas docs; match the parameters there and keep the intent obvious. - Use
sort_indexwhen sorting labels — When the intent is index order, call the index method rather than sorting a column by mistake:df_indexed = df.set_index("id").sort_index() - Keep chains pure — Build chains from methods that return objects:
df = ( raw.pipe(clean) .assign(rate=lambda d: d["wins"]/d["games"]) .sort_values("rate") )Every step returns a DataFrame; none of them is in-place, so the chain stays alive.
Why In-Place Often Causes Trouble
Short note: In Pandas, inplace=True usually sets the return value to None. That design reduces temporary copies but makes it easy to write df = some_inplace_op(...) by habit. The moment you assign that result, you overwrite your variable with None. The next access such as df.sort_values(...) triggers the error message in this article. Official docs for sort_values list inplace and show examples that use the returned DataFrame rather than assignment to the result of an in-place call. General Python guidance also warns that mutating methods often return None; the classic list .sort() example demonstrates the same rule in a simpler setting.
Edge Cases That Produce The Same Error
Not every stack trace with this text points at inplace. These cases deserve a quick pass:
- Shadowed variable — A helper reused the name
dffor another purpose and set it toNone. Rename locals or return values to keep scopes clean. - Conditional path with no return — A function returns a DataFrame in one branch and nothing in another. In Python, no return is
None. Add a default return or raise on missing data. - Misspelled method name — The real method is
sort_values(lowercase with underscore). A typo such asSort_Valuesfails, and if you already setdftoNoneupstream, the same string appears in the message. - Deprecated method — Old code that used
sorton DataFrames now fails. Replace withsort_valuesorsort_index. Community upgrade posts and notes point to this change.
Safe Refactors: From Fragile To Clear
Swap patterns that invite None with simple, readable code. These edits raise clarity and reduce footguns.
Turn In-Place + Assignment Into Pure Expressions
# Before
df = df.dropna(inplace=True)
df = df.sort_values("age", inplace=True)
# After
df = df.dropna()
df = df.sort_values("age")
Split Long Chains When Debugging
# Before
df = (load()
.query("age >= 18")
.merge(dim, on="k")
.sort_values("score")) # hard to see where None happened
# After
df = load()
print("loaded:", type(df))
df = df.query("age >= 18")
df = df.merge(dim, on="k")
df = df.sort_values("score")
Always Return A DataFrame From Helpers
def load_or_empty(path):
try:
df = pd.read_parquet(path)
except FileNotFoundError:
return pd.DataFrame() # not None
return df
Testing Patterns That Prevent Regressions
Small tests catch the exact failure that leads to AttributeError: ‘NoneType’ object has no attribute ‘Sort_Values’. These checks are tiny and pay off in minutes saved.
- Assert types after load — Confirm your loader returns a DataFrame:
df = load() assert isinstance(df, pd.DataFrame) - Lint for in-place — Add a simple search in CI that flags
inplace=Truein data code, or adopt a project rule to avoid it entirely. - Property tests for empty inputs — Feed empty frames to transforms and confirm they still return frames you can sort.
Performance Notes Without Pitfalls
Keep it clear: Many teams skip inplace because the speed win is small or absent for modern Pandas flows, while the risk of returning None is real. Favor returns you can chain and profile only when needed. When you do care about memory, measure the path on your data rather than guessing. For value sorting, stick to sort_values; when you only need label order, use sort_index instead.
Final Checks Before You Run
- Search for in-place assignment — Remove any
df = something(..., inplace=True). - Verify method names — Use
sort_valuesorsort_indexwith correct case. - Guarantee returns in helpers — Every code path should return a DataFrame, not
None. - Protect chains during refactors — Keep chains pure; split for debugging then re-compose.
- Confirm on empty data — Empty frames are still frames; do not swap them for
None.
References
Read these sources for signatures, patterns, and background:
- Pandas: DataFrame.sort_values reference
- Why methods that mutate often return None (Python pattern)
- DataFrame
.sortremoval and the right replacements - Step-by-step
sort_valuesusage guide
Extra: A Clean Template You Can Reuse
Drop this into your project and call the function instead of repeating sorting code. It keeps returns safe and chains clean.
import pandas as pd
def sort_safe(df: pd.DataFrame, by, ascending=True, kind="quicksort",
na_position="last", ignore_index=False, key=None) -> pd.DataFrame:
"""
Sort a DataFrame safely without in-place side effects.
Always returns a DataFrame; never returns None.
"""
if df is None:
raise TypeError("Expected DataFrame, got None")
return df.sort_values(by=by,
ascending=ascending,
kind=kind,
na_position=na_position,
ignore_index=ignore_index,
key=key)
Use it like this:
# Always returns a DataFrame you can keep chaining
df = sort_safe(df, by=["score", "date"], ascending=[False, True])
Follow these patterns and the error string AttributeError: ‘NoneType’ object has no attribute ‘Sort_Values’ will vanish from your logs. The same habits improve clarity across your data code, not just for sorting.
