# Python SDK: errors and batches

The SDK raises one of four errors, and each tells you whether the call reached Cady.

- `InputError`: the input was invalid. Nothing was sent.
- `AuthenticationError`: sign-in or the connection failed. Nothing was sent.
- `RefusalError`: Cady refused the call. `error.result` holds the refusal and its reason.
- `UncertainError`: the call could not be verified. It may have run.

```python
from cady_cli import CadyClient, RefusalError, UncertainError

async def read_work(company):
    async with CadyClient(company=company) as cady:
        try:
            return await cady.call("work_read")
        except RefusalError as error:
            print("refused:", error.result)
        except UncertainError:
            print("not verified: check the record before retrying")
```

The SDK never retries for you. After an `UncertainError` on a write, read the record first, then decide.

## Batches

```python
rows = await cady.batch([
    {"tool": "cady_read", "arguments": {"refs": ["company:setup"]}},
    {"tool": "work_read", "arguments": {}},
])
for row in rows:
    print(row["index"], row["status"])
```

```text
0 success
1 success
```

`batch` runs the calls in order and returns one row per call with `index` and `status`: `success`, `refused`, `uncertain` or `not_attempted`. It stops starting new calls after the first failure. The limits are the same as [cady local batch](https://cadyworks.com/docs/batch.md): 1,000 calls, 2 MiB, and `concurrency` from 1 to 8.

Next: [Your AI app, approvals and companies](https://cadyworks.com/docs/ai-app.md)
