affaan-m/ECC · warning · NotFoundError
User not found: {user_id}
Error message
User not found: {user_id} What it means
A NotFoundError (subclass of AppError) raised by get_user() when db.find_user(user_id) returns a falsy value. It indicates the requested user does not exist in the data store. It is part of a custom exception hierarchy (AppError -> NotFoundError) intended for domain-level control flow.
Source
Thrown at skills/python-patterns/SKILL.md:194
```python
class AppError(Exception):
"""Base exception for all application errors."""
pass
class ValidationError(AppError):
"""Raised when input validation fails."""
pass
class NotFoundError(AppError):
"""Raised when a requested resource is not found."""
pass
# Usage
def get_user(user_id: str) -> User:
user = db.find_user(user_id)
if not user:
raise NotFoundError(f"User not found: {user_id}")
return user
```
## Context Managers
### Resource Management
```python
# Good: Using context managers
def process_file(path: str) -> str:
with open(path, 'r') as f:
return f.read()
# Bad: Manual resource management
def process_file(path: str) -> str:
f = open(path, 'r')
try:
return f.read()View on GitHub (pinned to 01e15490f0)
Solutions
- Confirm the user_id exists in the data source with a direct query.
- Check whether a soft-delete filter or tenant scope is excluding the row.
- Handle the race: re-fetch or use a transaction if a concurrent delete is possible.
- Catch NotFoundError at the handler/controller layer and map it to an HTTP 404 response rather than a 500.
Example fix
# before
user = db.find_user(user_id)
if not user:
raise NotFoundError(f"User not found: {user_id}")
# after: distinguish not-found from deleted at the boundary
user = db.find_user(user_id, include_deleted=False)
if user is None:
existing = db.find_user(user_id, include_deleted=True)
if existing is not None:
raise GoneError(f"User deleted: {user_id}")
raise NotFoundError(f"User not found: {user_id}") Defensive patterns
Strategy: try-catch
Validate before calling
def user_exists(user_id: str) -> bool:
return db.find_user(user_id) is not None
if not user_exists(user_id):
return http_response(404, {"error": "user not found"}) Type guard
null
Try / catch
from myapp.errors import NotFoundError
try:
user = get_user(user_id)
except NotFoundError:
return respond_404(user_id)
else:
return respond_200(user) Prevention
- Catch the domain NotFoundError only at the controller/handler boundary, not in the repository.
- Map it to 404, not 500.
- Avoid echoing whether an id exists to prevent enumeration.
When it happens
Trigger: Calling get_user(user_id) with an id that has no matching row; the database lookup returned None, an empty result, or an empty ORM object; the id was deleted between lookup and access.
Common situations: Stale references in a URL after a user is deleted; race condition between delete and read; typo in an id passed from a route parameter; soft-deleted records excluded by a default query filter.
Related errors
- Unable to load issue #${issueNumber} from ${repo}
- Memory ${memoryId} was not found.
- Claude session not found: ${explicitTarget}
- Codex rollout session not found: ${explicitTarget}
- OpenCode session not found: ${explicitTarget}
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/7ec3f3c290ec341e.
Report an issue: GitHub.