> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nodemaven.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Check connections and handle SDK errors

> Run a connection check and distinguish configuration, gateway, network, and account API errors.

Test an HTTP proxy connection and distinguish configuration errors from gateway, network, and account API failures.

Start here when your configuration builds but your requests do not work as expected. The SDK's connection check reads the proxy gateway's response directly, which can be easier to inspect than an HTTP client's generic proxy error.

## Run a connection check

Use the credentials and installation from your [Python](https://docs.nodemaven.com/developer-sdks/python.md), [Rust](https://docs.nodemaven.com/developer-sdks/rust.md), or [Go](https://docs.nodemaven.com/developer-sdks/go.md) quickstart. These are complete programs; each checks an HTTP proxy and exits unsuccessfully if the gateway refuses it.

**Python**

```python theme={null}
from nodemaven import Proxy

proxy = Proxy(country="us", filter="medium")
result = proxy.check()
print(result)

if not result.ok:
    raise SystemExit("Gateway refused the connection; review the status above.")
```

**Rust**

```rust theme={null}
fn main() -> Result<(), Box<dyn std::error::Error>> {
    let proxy = nodemaven::Proxy::builder()
        .param("country", "us")
        .param("filter", "medium")
        .build()?;
    let result = proxy.check()?;
    println!("{result}");
    if !result.ok() {
        return Err("Gateway refused the connection; review the status above.".into());
    }
    Ok(())
}
```

**Go**

```go theme={null}
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/nodemaven/nodemaven-go"
)

func main() {
    if err := run(); err != nil {
        log.Fatal(err)
    }
}

func run() error {
    proxy, err := nodemaven.New(
        nodemaven.WithParam("country", "us"),
        nodemaven.WithParam("filter", "medium"),
    )
    if err != nil {
        return err
    }
    result, err := proxy.Check(context.Background())
    if err != nil {
        return err
    }
    fmt.Println(result)
    if !result.OK() {
        return fmt.Errorf("gateway refused the connection; review the status above")
    }
    return nil
}
```

A successful result can look like this:

```text theme={null}
200 Connection established via gate.nodemaven.com:8080 in 0.42s, exit 203.0.113.42
```

The timing and IP above are illustrative. An exit IP is displayed only when the gateway includes it in the reply. A successful check without an IP is a normal result; use a request to an IP echo service when you need to read the address consistently.

## What the check proves

The check opens one HTTP CONNECT tunnel, by default to `api.ipify.org:443`, with a 15-second timeout. It reads the gateway response and closes the connection without fetching a page through the tunnel. The target can still see a TCP connection from the proxy exit.

A `200` means the tunnel opened. It does not prove that a website will return the page you need, that a browser is configured correctly, or that every product property has been verified. Follow it with a real request from the same client your application uses.

**A gateway refusal is a result, not an exception or Go error.** Inspect `result.ok` in Python, `result.ok()` in Rust, or `result.OK()` in Go. A returned `407` can otherwise look like a successful function call.

The check uses HTTP CONNECT even if you built a URL with a different scheme. Do not point it at a SOCKS5 port to test SOCKS5.

## Change the target or timeout

These fragments reuse `proxy` from the check program. In Rust, use them before `Ok(())`. In Go, add `time` to the imports and use the fragment inside `run`.

**Python**

```python theme={null}
result = proxy.check(target="example.com:443", timeout=30.0)
```

**Rust**

```rust theme={null}
let result = proxy
    .connect()
    .target("example.com:443")
    .timeout(std::time::Duration::from_secs(30))
    .send()?;
```

**Go**

```go theme={null}
connect := proxy.Connect()
connect.Target = "example.com:443"
connect.Timeout = 30 * time.Second
customResult, err := connect.Send(context.Background())
if err != nil {
    return err
}
fmt.Println(customResult)
```

Changing the check timeout does not change the timeout in your application HTTP client.

## Recognize SDK errors

| Situation | Python | Rust | Go |
| - | - | - | - |
| Unknown parameter, empty value, or unsupported formatting | `ParamError` | `Error::Param` | `ErrParam` |
| Missing credential or invalid gateway address/port | `CredentialsError` | `Error::Credentials` | `ErrCredentials` |
| Invalid custom gateway definition | `ProviderError` | `Error::Provider` | `ErrProvider` |
| No usable HTTP CONNECT response | `CheckError` | `Error::Check` | `ErrCheck` |
| Account API failure or unreadable response | `ApiError` | `Error::Api` | `ErrAPI` |
| Account API returns 401 or 403 | `AuthError` | `Error::Auth` | `ErrAuth` |
| Account API returns 404 | `NotFoundError` | `Error::NotFound` | `ErrNotFound` |
| Account API returns 429 | `RateLimitError` | `Error::RateLimit` | `ErrRateLimit` |

Formatting checks account for the [normalization rules](https://docs.nodemaven.com/developer-sdks/configuration.md): a space in `New York` is handled differently from a space in a session ID.

All Python SDK exceptions inherit from `NodeMavenError`. API-specific exceptions inherit from `ApiError`. In Rust, account API errors also expose their status through `error.status()`. In Go, use `errors.Is` rather than comparing error strings.

## Handle local configuration errors

These fragments demonstrate an intentional typo. They do not make a network request. Go needs the standard-library `errors` and `fmt` imports.

**Python**

```python theme={null}
from nodemaven import ParamError, Proxy

try:
    Proxy(login="example_user", password="example_password", contry="us")
except ParamError:
    print("Unknown proxy parameter: use country, not contry.")
```

**Rust**

```rust theme={null}
match nodemaven::Proxy::builder()
    .login("example_user")
    .password("example_password")
    .param("contry", "us")
    .build()
{
    Err(nodemaven::Error::Param(_)) => {
        println!("Unknown proxy parameter: use country, not contry.");
    }
    Err(error) => return Err(error.into()),
    Ok(_) => return Err("Expected the invalid parameter to be rejected.".into()),
}
```

**Go**

```go theme={null}
_, err := nodemaven.New(
    nodemaven.WithLogin("example_user"),
    nodemaven.WithPassword("example_password"),
    nodemaven.WithParam("contry", "us"),
)
if errors.Is(err, nodemaven.ErrParam) {
    fmt.Println("Unknown proxy parameter: use country, not contry.")
} else if err != nil {
    return err
} else {
    return fmt.Errorf("expected the invalid parameter to be rejected")
}
```

## Interpret gateway responses

A status code is a starting point, not a complete diagnosis. The SDK's gateway definition includes explanations from observed responses.

| Status or symptom | What to check |
| - | - |
| **407 Proxy Authentication Required** | Both credentials and parameter values. Unsupported country, filter, lifetime, type, or speed values can also produce 407. Check the lowercase lifetime unit. |
| **406 Not Acceptable** | Country/region/city/carrier combinations and current availability. A 406 does not identify which individual value caused the refusal. |
| **410 Gone** | Carrier targeting. The SDK's observations include an ISP-specific refusal; do not assume every 410 has the same cause. Try a carrier from the current catalogue or remove carrier targeting. |
| **500 Internal Server Error** | First check whether you supplied `city` without its `region`. Other 500 responses can have unrelated causes. |
| **402 Payment Required** | Available traffic and plan status in the dashboard. |
| **No usable response** | Gateway hostname, HTTP port, network access, DNS, and timeout. Use [Verify with curl](https://docs.nodemaven.com/troubleshooting/verify-with-curl.md) to compare. |

For the same failure, `requests`, `reqwest`, or another client may raise a proxy/transport exception instead of exposing a normal HTTP response object. Distinguish the gateway's CONNECT status from the target website's HTTP status.

## If the check succeeds but your task fails

* **Your own IP is returned:** confirm the application's client uses the SDK output. A new proxy object does not reconfigure an existing client.
* **The website returns 403, 429, or a challenge:** inspect the target response, request rate, session handling, and the website's access requirements. A successful tunnel is not a guarantee of website access.
* **A sticky exit changes:** check its lifetime, availability, and whether targeting or filters changed. See [Manage sessions](https://docs.nodemaven.com/developer-sdks/sessions.md).
* **The account API fails:** verify `NODEMAVEN_APIKEY`, not the proxy password. For 429, use a bounded retry policy with backoff. The SDK does not retry automatically; its built-in API client does not expose a reliable `Retry-After` header.

When contacting support, include the SDK version, error category or status, target hostname, and a minimal example. Remove proxy passwords, API keys, authenticated URLs, and full account API responses.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.