# Troubleshooting

Common errors and how to fix them when using the Lume SDK.

---

## GraphQLError: unauthorized

**Symptom:** Any API call raises `GraphQLError` with a message containing
"unauthorized" or "authentication failed".

**Cause:** The private key is missing, invalid, or does not correspond to a
registered user.

**Fix:**

1. Verify the `PRIVATE_KEY` environment variable is set and is a valid hex
   string (with or without `0x` prefix):
   ```bash
   echo $PRIVATE_KEY
   ```
2. Confirm the key is 64 hex characters (32 bytes):
   ```python
   key = os.environ["PRIVATE_KEY"].replace("0x", "")
   assert len(key) == 64, f"Expected 64 hex chars, got {len(key)}"
   ```
3. If this is a new wallet, you may need to register it first by calling
   `client.update_proxy_wallet()` before placing orders.

---

## ValueError: Outcome not found

**Symptom:** `create_and_place_order()` or `get_orderbook()` raises:

```
ValueError: Outcome 'Yes' not found. Available outcomes: YES, NO
```

**Cause:** The outcome label does not match any outcome in the market. Labels
are compared case-insensitively but must match the actual label text.

**Fix:**

1. Check the exact outcome labels for the market:
   ```python
   market = client.get_market("<MARKET_UUID>")
   for o in market.outcomes:
       print(o.label)  # e.g., "YES", "NO"
   ```
2. Use the exact label string. Common labels are `"YES"` and `"NO"` for binary
   markets. Categorical markets may have custom labels like `"Republican"`,
   `"Democrat"`, etc.
3. The comparison is case-insensitive, so `"yes"`, `"Yes"`, and `"YES"` all
   work. But `"Y"` or `"Ja"` will not match `"YES"`.

---

## WebSocketError: connection timeout / connection closed

**Symptom:** Subscription methods fail with `WebSocketError` about connection
timeouts or unexpected closures.

**Causes and fixes:**

1. **Network issue:** Check your internet connection and that the API URL is
   reachable:

   ```python
   print(client.api_url)   # HTTP endpoint
   print(client.ws_url)    # WebSocket endpoint (auto-derived)
   ```

2. **Wrong API URL:** If using a custom URL, ensure it does not have a trailing
   slash issue. The SDK auto-derives the WebSocket URL from the HTTP URL.

3. **Firewall blocking WebSocket:** Some firewalls block `wss://` connections.
   Try from a different network.

4. **Server restart:** The server may have restarted. Reconnect:

   ```python
   await client.close_websocket()
   # Subscriptions auto-reconnect on next use
   async for update in client.subscribe_to_order_updates():
       ...
   ```

5. **Stale connection:** If the connection has been idle for too long, close and
   reopen:
   ```python
   await client.close_websocket()
   await client.connect_websocket()
   ```

---

## Proxy wallet is None

**Symptom:** `client.proxy_wallet` returns `None`, or orders fail because the
proxy wallet is not set.

**Cause:** The user account does not have a proxy (Safe) wallet registered yet.

**Fix:**

If using `AgentClient`, call `register()` which automatically sets up the proxy
wallet:

```python
from lume import AgentClient

agent = AgentClient(private_key=os.environ["PRIVATE_KEY"])
info = agent.register()
print(f"Proxy wallet: {agent.proxy_wallet}")
```

If using `LumeClient` directly, call `update_proxy_wallet()`:

```python
client.update_proxy_wallet()
print(f"Proxy wallet: {client.proxy_wallet}")
```

---

## Price format confusion

**Symptom:** Orders are placed at wildly wrong prices, or amounts look
nonsensical.

**Cause:** Mixing up human-readable values and atomic units.

**Key rules:**

| Context                     | Format               | Example                                        |
| --------------------------- | -------------------- | ---------------------------------------------- |
| `OrderArgs.price`           | Human-readable float | `0.50`                                         |
| `OrderArgs.size`            | Human-readable float | `100.0`                                        |
| API response `order.price`  | Atomic string        | `"500000"`                                     |
| API response `order.shares` | Atomic string        | `"100000000"`                                  |
| `to_atomic()` input         | Human-readable       | `to_atomic(0.50)` -> `500000`                  |
| `from_atomic()` input       | Atomic int           | `from_atomic(500000)` -> `Decimal('0.500000')` |

**Fix:** When displaying API values, always convert:

```python
from lume import from_atomic

order = client.get_order("<ORDER_UUID>")
print(f"Price: ${from_atomic(int(order.price))}")    # NOT order.price directly
print(f"Price: ${order.price_decimal}")               # Or use the property
```

When creating orders, use plain decimals:

```python
# Correct
OrderArgs(price=0.50, size=100.0, ...)

# WRONG - do not pass atomic units to OrderArgs
OrderArgs(price=500000, size=100000000, ...)
```

---

## LUME_ENV not set / wrong environment

**Symptom:** Client connects to the wrong network (dev vs prod), or raises
`RuntimeError` about placeholder config.

**Cause:** The `LUME_ENV` environment variable controls which network config is
used. It defaults to `prod` (Monad Mainnet, chain_id=143).

**Fix:**

```bash
# For development/testing (Monad Testnet)
export LUME_ENV=dev

# For production (Monad Mainnet)
export LUME_ENV=prod
```

To verify which environment is active:

```python
from lume.constants import get_lume_env, get_config_with_env_overrides

print(f"Environment: {get_lume_env()}")
cfg = get_config_with_env_overrides()
print(f"API URL:     {cfg.api_url}")
print(f"Chain ID:    {cfg.chain_id}")
```

You can also override individual settings without changing `LUME_ENV`:

```bash
export LUME_API_URL="https://custom-api.example.com/query"
export LUME_CHAIN_ID=143
```

---

## GraphQLError: insufficient balance / collateral

**Symptom:** Placing an order fails with a message about insufficient balance or
collateral.

**Fix:**

1. Check your balance:

   ```python
   bal = client.get_onchain_balance()
   print(f"Available: {bal['available']}")
   print(f"Locked:    {bal['locked']}")
   ```

2. The `available` amount must cover the order cost (`price * size` for BUY
   orders). Remember that collateral is shared across markets within an event.

3. If you need to add funds, deposit USDC via `SafeExecutor.deposit_funds()`.

---

## GraphQLError: insufficient shares to sell

**Symptom:** A SELL order fails with a message about insufficient shares.

**Cause:** You are trying to sell more shares than you own for that outcome.

**Fix:**

1. Check your positions:

   ```python
   pos = client.get_my_positions("<MARKET_UUID>")
   for p in pos["positions"]:
       print(f"{p['outcome']['label']}: {p['shares']} shares")
   ```

2. Reduce the sell size to match your holdings.

3. To bet against an outcome, BUY the opposite outcome instead of selling:
   ```python
   # Instead of selling YES, buy NO
   OrderArgs(side=OrderSide.BUY, outcome="NO", ...)
   ```

---

## SafeNotDeployedError

**Symptom:** `SafeExecutor` raises `SafeNotDeployedError` when trying to
execute on-chain transactions.

**Cause:** The Gnosis Safe wallet has not been deployed on-chain yet.

**Fix:**

Deploy the Safe first using `SafeWalletManager`:

```python
from lume import SafeWalletManager

mgr = SafeWalletManager(
    private_key=os.environ["PRIVATE_KEY"],
    rpc_url="https://rpc.monad.xyz",
)

# Check if deployed
address = mgr.compute_safe_address()
print(f"Predicted address: {address}")
print(f"Deployed: {mgr.is_safe_deployed(address)}")

# Deploy if needed
safe_address = mgr.create_safe_wallet()
print(f"Safe ready at: {safe_address}")
```

---

## ImportError: No module named 'lume'

**Symptom:** Python cannot find the `lume` package.

**Fix:**

Install from the repository:

```bash
pip install git+https://github.com/EternisAI/lume-sdk.git
```

If developing locally:

```bash
cd /path/to/lume-sdk
pip install -e .
```

---

## Onboarding not complete / relay fee not paid

**Symptom:** `relay_safe_transaction()` fails with a message about onboarding
not being complete or relay fee not paid.

**Cause:** The agent has not completed all onboarding steps. The gasless relay
requires: (1) Safe deployed, (2) approvals set, and (3) relay fee paid.

**Fix:**

1. Check the current onboarding status:

   ```python
   status = agent.get_onboarding_status()
   print(f"Safe deployed:       {status.safe_deployed}")
   print(f"Approvals completed: {status.approvals_completed}")
   print(f"Relay fee paid:      {status.relay_fee_paid}")
   print(f"Fully onboarded:     {status.is_fully_onboarded}")
   if status.next_step:
       print(f"Next step:           {status.next_step.value}")
   ```

2. Complete the missing step(s):
   - If Safe not deployed or approvals not set: call `register_wallet_user()`
   - If relay fee not paid: ensure the Safe has at least 1 USDC, then call
     `pay_relay_fee()`

3. See `examples/safe_wallet_operations.py` for the full onboarding flow.

---

## Order context not found

**Symptom:** `create_and_place_order()` fails with "order context not found".

**Cause:** The agent's wallet is not properly registered or the backend cannot
find the user's trading context. This can happen if:

- The agent has not called `register()` yet
- The proxy wallet is not set up

**Fix:**

1. Ensure the agent is registered:

   ```python
   info = agent.register()
   print(f"User ID: {info.user_id}")
   print(f"Proxy wallet: {agent.proxy_wallet}")
   ```

2. Verify the agent is fully onboarded:

   ```python
   status = agent.get_onboarding_status()
   print(f"Fully onboarded: {status.is_fully_onboarded}")
   ```

3. Ensure the Safe has USDC balance. The backend syncs on-chain balance during
   order placement.

---

## Connection refused / Cannot reach API

**Symptom:** `GraphQLError` with connection errors.

**Fix:**

1. Verify the API URL is reachable:

   ```python
   print(client.api_url)
   ```

2. For dev environment, the default URL is:
   `https://server-graphql-dev.up.railway.app/query`

3. For prod environment, the default URL is:
   `https://server-graphql-prod.up.railway.app/query`

4. If using a custom URL, ensure it includes the path (e.g., `/query`).

5. Check if the service is up by visiting the URL in a browser or with curl:
   ```bash
   curl -s https://server-graphql-dev.up.railway.app/query \
     -H "Content-Type: application/json" \
     -d '{"query":"{ __typename }"}'
   ```
