The error means your code is calling .people on a None value; fix by ensuring the object isn’t None or installing missing dependencies.
Seeing attributeerror: 'nonetype' object has no attribute 'people' can stall a script or a deployment. The message is plain: Python raised an AttributeError because your code tried to access .people on a variable that currently holds None. The fix is twofold: confirm why that variable is None, and add a safe path when it is. In a few Linux cases (like adding a PPA) the message points to a missing package, not your Python logic. This guide walks you through fast checks, deeper diagnosis, and reliable patterns to prevent the crash next time.
What The Error Means
Quick check: an AttributeError appears when attribute access fails on a given object. If the object is None, any attribute lookup raises the same error. In short, Python didn’t find a real object with a .people attribute; it found None.
# Repro
user_dir = None
print(user_dir.people) # <-- AttributeError: 'NoneType' object has no attribute 'people'
Why this happens: the value came from a function that returned nothing, a failed API call, a dictionary lookup that missed, or a branch that skipped initialization. The cure is to guarantee a valid object before you call .people, or guard the call with a fallback.
# Guard pattern
people = user_dir.people if user_dir is not None else []
Fast Fixes You Can Try Now
- Return A Real Value — If a helper ends without
return, Python returnsNone. Add an explicitreturnso callers don’t receiveNone. - Check The Source — Print or log the variable right before the failing line to confirm whether it’s
Noneand where it came from. - Add A Guard — Wrap the attribute access in a short check:
if obj and obj.people:or use a default likeobj.people if obj else []. - Validate External Calls — When a network or database call can fail, handle the empty path and skip the
.peoplecall until you have data. - Use Type Hints — Mark a return as
Optional[T]so editors and linters flag paths that forget to handleNone.
Nonetype Object Has No Attribute People — Common Causes
Missed return: a function computes a value but never returns it. Callers then receive None and the next attribute access fails.
def load_user_dir(config):
if not config.home:
return None
path = build_path(config.home)
# forgot: return Directory(path)
user_dir = load_user_dir(cfg) # user_dir is None
team = user_dir.people # blows up
Chained calls: one link returns None, so the next link fails.
team = client.get_org(name).get_directory().people # any step can be None
Lookup miss: a dict or query returns nothing. Safe code checks first.
org = cache.get("org") # may be None
team = org.people if org else []
Conditional init: a branch creates the object only for some inputs. Add a default init path or handle the empty branch.
Linux Case: add-apt-repository Shows “People”
On some Debian/Ubuntu hosts, running sudo add-apt-repository ppa:<name> throws attributeerror: 'nonetype' object has no attribute 'people'. The usual fix is to install the Launchpad client library so the tool can reach the Launchpad People endpoint cleanly.
- Install Launchpadlib —
sudo apt-get install python3-launchpadlib. - Re-run The Command — Try the same
add-apt-repositoryagain. - Confirm Versions — Stick to a supported Ubuntu LTS when using PPAs; older combinations can break the helper.
This variant isn’t your Python script’s fault. It’s a packaging gap: the helper expects Launchpad bindings, and without them a None object slips through where a Launchpad client should be. Installing the library restores a real object, so .people resolves as intended.
Step-By-Step Debug Routine
Print the value: confirm the variable is truly None with a one-line log right before the failure. Keep the message short and specific.
print("user_dir =", repr(user_dir))
Trace the source: search upward for where the variable is set. If it comes from a function, open that function and check every branch for a return.
def load_user_dir(config) -> Optional[Directory]:
if not config.home:
return None
return Directory(build_path(config.home)) # explicit return
Harden the call site: short-circuit when the value is empty so the flow still succeeds.
user_dir = load_user_dir(cfg)
if not user_dir:
log.warning("No user directory; skipping team fetch")
team = []
else:
team = user_dir.people
Add tests: write one test where the provider returns None and assert your code doesn’t crash.
def test_people_empty_when_no_dir(mocker):
mocker.patch("app.load_user_dir", return_value=None)
team = get_team()
assert team == []
Table: Signals, Likely Causes, Fixes
| Signal You See | Likely Cause | Fix |
|---|---|---|
'NoneType' has no attribute 'people' on your code path |
Function forgot to return a real object | Add an explicit return; add a guard at the call site |
| Crash after a long chain of calls | One link in the chain returned None |
Split the chain; check each step; handle empty |
Error during add-apt-repository |
Missing Launchpad client library | Install python3-launchpadlib; retry |
Make The Fix Stick
- Prefer Early Returns — Return fast when inputs are invalid; don’t let a
Noneleak into later code. - Use Guard Expressions — Pick compact forms that keep the flow clear:
team = dir.people if dir else []. - Fail Loudly In Dev — In debug builds, assert that a value is not
Nonewhen your contract requires a real object. - Annotate With Optional — Mark types as
Optionalto nudge IDEs and CI to flag missed checks. - Split Long Chains — Assign each step to a named variable; log early when a step returns
None.
# Before (fragile)
team = client.get_org(name).get_directory().people
# After (robust)
org = client.get_org(name)
if not org:
return []
directory = org.get_directory()
if not directory:
return []
return directory.people
AttributeError: ‘NoneType’ Object Has No Attribute ‘People’ — When To Handle vs. Fix At The Source
Fix at the source: when a value is None due to a clear bug (missed return, wrong key, bad path), correct the logic so callers always get a valid object. That keeps downstream code clean and readable.
Handle at the edge: when None is a defined, acceptable outcome (empty query result, optional section, flaky network), keep a short guard at the boundary and pass along a safe default such as an empty list. That turns a crash into a no-op or a user-friendly message.
Extra Patterns For Safer Code
- Dataclass Defaults — Provide defaults that aren’t
Nonewhere practical. - Factory Functions — Centralize object creation so only one place can return
None. - Small, Clear Functions — Short functions make it easy to see where
Nonemight appear. - Logging With Context — Include the key and the path you looked up when recording a miss.
from dataclasses import dataclass, field
from typing import List
@dataclass
class Directory:
people: List[str] = field(default_factory=list)
def directory_from(config) -> Directory:
if not getattr(config, "home", None):
return Directory() # non-None default
return Directory(load_members(config.home))
When It’s Not Your Code
Tooling and third-party packages can raise the same message. If the stack trace points into a library or a system helper, search for an open issue tied to your version and platform. When the crash appears during repository setup on Debian or Ubuntu, install the Launchpad library and try again. If the trace shows an IDE or debugger frame, update the plugin or toolchain and re-run. Keep your fix local when you can, and update dependencies when the message originates outside your project.
With these checks and patterns in place, you can turn attributeerror: 'nonetype' object has no attribute 'people' from a blocker into a quick fix, then into a problem you rarely see again.
