# How `Result` Objects Humanize Network Errors in user-scanner

> Discover how user-scanner's Result objects humanize network errors by converting exceptions into readable messages with the humanize_exception function. Learn more now.

- Repository: [Kaif/user-scanner](https://github.com/kaifcodec/user-scanner)
- Tags: internals
- Published: 2026-09-02

---

**The `Result` class converts low-level network exceptions into readable messages using the `humanize_exception` helper function, which pattern-matches error strings and returns user-friendly descriptions.**

The `user-scanner` library by kaifcodec handles network scanning operations where connection failures, DNS errors, and timeouts are common. Rather than exposing raw exception traces to users, the `Result` object in [`user_scanner/core/result.py`](https://github.com/kaifcodec/user-scanner/blob/main/user_scanner/core/result.py) transforms these technical errors into actionable, human-readable explanations.

## The `humanize_exception` Function

Network error humanization happens in the `humanize_exception` function (lines 48–66 of [`user_scanner/core/result.py`](https://github.com/kaifcodec/user-scanner/blob/main/user_scanner/core/result.py)). This helper inspects the exception string using case-insensitive pattern matching against known system error codes and network failure signatures.

When implemented, the function checks for these specific patterns:

| Pattern detected | Human-readable message |
|------------------|------------------------|
| `"10054"` | "Connection closed by remote server" |
| `"11001"` | "Could not resolve hostname" |
| `"errno 7"` or `"no address associated with hostname"` | "No internet connection or DNS failure" |
| `"errno 101"` or `"network is unreachable"` | "Network unreachable (Is your internet on?)" |
| `"curl: (28)"` or `"connection timed out"` | "Connection timed out (try a VPN if the site is blocked in your region)" |

If no pattern matches, the function returns the original exception message unchanged. This fallback ensures that unrecognized errors still provide diagnostic information rather than failing silently.

## How `Result` Applies Humanization

The `Result` class integrates humanization through its `get_reason()` method. When a `Result` is created with an exception via `Result.error()`, the `reason` attribute stores that exception. The `get_reason()` method detects when `reason` is an exception instance and automatically passes it to `humanize_exception` for transformation.

This design ensures consistency across all output formats—console display, `__str__` representation, CSV exports, and JSON serialization—all present the same readable error descriptions.

### Creating Humanized Error Results

```python
from user_scanner.core.result import Result, humanize_exception

# Simulate a network timeout from curl

exc = Exception("curl: (28) Connection timed out after 30 seconds")
result = Result.error(exc)

print(result.get_reason())

# → "Exception: Connection timed out (try a VPN if the site is blocked in your region)"

```

### DNS and Connectivity Failures

```python

# Simulate a DNS resolution failure

exc = Exception("errno 7 - No address associated with hostname")
result = Result.error(exc)

print(result.get_reason())

# → "Exception: No internet connection or DNS failure"

```

### Unrecognized Errors Pass Through

```python

# When no pattern matches, the original message is preserved

exc = Exception("random unexpected error")
result = Result.error(exc)

print(result.get_reason())

# → "Exception: random unexpected error"

```

## Pattern Coverage and Extensibility

The current implementation targets the most common network failure modes across different underlying libraries:

- **Winsock errors** (10054, 11001) — Windows socket layer failures
- **POSIX errno codes** (7, 101) — UNIX system-level network errors
- **libcurl error codes** (28) — HTTP client timeout conditions
- **Generic network unreachable** — Cross-platform connectivity detection

The lower-case string comparison in `humanize_exception` ensures case-insensitive matching regardless of how the underlying library formats its error messages. This robustness is important because different Python versions, operating systems, and network libraries present identical errors with varying capitalization.

## Testing Humanization Behavior

The humanization logic is verified in [`tests/test_result.py`](https://github.com/kaifcodec/user-scanner/blob/main/tests/test_result.py), which contains unit tests confirming that `Result` correctly formats reasons including the network-error transformation pipeline. These tests validate both pattern matching accuracy and the fallback behavior for unknown exceptions.

## Summary

- **`humanize_exception`** in [`user_scanner/core/result.py`](https://github.com/kaifcodec/user-scanner/blob/main/user_scanner/core/result.py) (lines 48–66) performs pattern-based translation of network errors
- **`Result.get_reason()`** automatically applies humanization when the stored reason is an exception
- **Five core error patterns** cover connection resets, DNS failures, unreachable networks, and timeouts
- **Fallback preservation** ensures unrecognized errors remain visible for debugging
- All output channels (**`__str__`**, **CSV**, **JSON**) receive the same humanized messages

## Frequently Asked Questions

### What happens if `humanize_exception` doesn't recognize an error pattern?

The original exception message is returned unchanged. This fallback ensures diagnostic information is never lost, allowing developers to see raw error details when encountering uncommon or new failure modes.

### Does `humanize_exception` modify the exception object itself?

No, it only transforms the string representation used for display. The original exception remains intact in `Result.reason`, accessible for programmatic handling or logging if needed.

### Can I use `humanize_exception` independently of `Result` objects?

Yes, the function is importable from `user_scanner.core.result` and can be called directly with any exception instance. This allows custom error handling pipelines to leverage the same humanization logic.

### Why does the timeout message suggest using a VPN?

The pattern `"curl: (28)"` often appears when sites are region-blocked or filtered by network infrastructure, not just during genuine connectivity failures. The VPN suggestion helps users distinguish between local network problems and access restrictions.