# Troubleshooting Guide
Common issues and solutions when using rust-ibapi.
## Build & Compilation Issues
### No Client Feature Enabled
**Error:**
```
error: You must enable at least one of the 'sync' or 'async' features to use this crate.
```
**Solution:**
Default features are off and neither client is enabled. In a dependency, add one back in `Cargo.toml`:
```toml
ibapi = { version = "5.2", default-features = false, features = ["async"] }
# OR
ibapi = { version = "5.2", default-features = false, features = ["sync"] }
```
When building this repository with `--no-default-features`, add `--features sync` or `--features async` to the command.
## Connection Issues
### Connection Refused
**Error:**
```
Error: Connection refused (os error 111)
```
**Solutions:**
1. **Start IB Gateway/TWS** - Ensure it's running
2. **Check port number:**
- IB Gateway Paper: 4002
- IB Gateway Live: 4001
- TWS Paper: 7497
- TWS Live: 7496
3. **Verify API is enabled** in IB Gateway/TWS settings
### API Not Configured
**Error:**
```
Error: API connection not configured
```
**Solution:**
Configure IB Gateway/TWS:
1. Go to **Configuration → API → Settings**
2. Enable **"Enable ActiveX and Socket Clients"**
3. Add **127.0.0.1** to trusted IPs
4. Disable **"Read-Only API"** if you need to place orders
5. Set **Master API client ID** if needed
### Connection Timeout
**Error:**
```
Error: Connection timeout
```
**Solutions:**
1. Check firewall settings
2. Verify IB Gateway/TWS is accepting connections
3. Ensure correct IP address (usually 127.0.0.1 for local)
4. Try increasing connection timeout in code
## Time Zones
### Gateway Time Zone
IB Gateway reports times as a wall-clock reading plus a zone name, such as
`20261009 10:00:00 US/Eastern`. The crate resolves the name to an IANA zone to
turn the reading into an instant. The zone is used in three places:
| `Client::time_zone()`, `Client::connection_time()` | the connection handshake (the gateway host's OS locale) | both `None`, warning logged at connect; the connection succeeds |
| `HistoricalDataEnd` start/end | each timestamp, when the gateway sends instrument time zone (the default) | `Error::UnsupportedTimeZone` |
| `HistoricalSchedule` sessions | the schedule's `time_zone` field | `Error::UnsupportedTimeZone` |
It is not used anywhere else. Historical request end dates are always sent in
UTC, and bar and tick timestamps arrive as epoch seconds. Text time fields such
as `Execution::time` and `OrderState::completed_time` are passed through as the
gateway sent them, not parsed. `Client::time_zone()` is informational: the crate
never converts your data with it.
Setting the gateway's "Send instrument-specific attributes ... in" option to
UTC format makes `HistoricalDataEnd` timestamps zone-less, so they need no lookup.
**Lookup order** (first match wins, names are matched exactly):
1. Aliases you register (`register_timezone_alias`, `IBAPI_TIMEZONE_ALIASES`)
2. The built-in alias table (non-standard names gateways are known to send, e.g. `BRT`, `China Standard Time`)
3. Mojibake from a Chinese-locale gateway → `Asia/Shanghai`
4. IANA names (`America/Sao_Paulo`, `US/Eastern`) and Windows registry ids (`E. South America Standard Time`)
A reading in a daylight-saving fold (clocks went back) takes the earlier
offset; one in a gap (clocks went forward) is pushed forward by the gap.
### Unrecognized Time Zone
**Symptom:** one of the outcomes in the table above, with this text in the
connect warning or the error:
```
unrecognized IB Gateway timezone "Some Standard Time"; register a mapping with
`ibapi::register_timezone_alias("Some Standard Time", "<IANA-name>")` ...
```
On non-English Windows the name may be a locale-specific label or mojibake.
Extend the alias table at runtime without rebuilding:
**Option 1 — programmatic (one mapping at a time):**
```rust
ibapi::register_timezone_alias("Some Standard Time", "America/New_York");
let client = Client::connect("127.0.0.1:4002", 100).await?;
```
Call `register_timezone_alias` before `Client::connect`. User-registered
aliases override the built-ins, so you can correct a default you disagree
with as well as add new ones.
**Option 2 — environment variable (multiple mappings, no code change):**
```bash
export IBAPI_TIMEZONE_ALIASES="Some Standard Time=America/New_York;Other=Europe/Berlin"
cargo run --example connect
```
The format is `name=iana` pairs separated by `;`. Whitespace around tokens is
trimmed. Malformed entries are logged at warn level and skipped.
To verify a mapping is being applied, run with `RUST_LOG=ibapi::common::timezone=debug`
and look for `timezone alias matched (registry): ...`.
If you find a label that should be a built-in (a common Windows locale name
not yet in our table), please file an issue at
<https://github.com/wboayue/rust-ibapi/issues> with the exact string the
gateway is sending.
## Market Data Issues
### No Market Data Permissions
**Error:**
```
Error: No market data permissions for SYMBOL
```
**Solution:**
Your IB account needs market data subscriptions:
1. Log into IB Account Management
2. Subscribe to required market data
3. Wait for activation (can take a few minutes)
4. Restart IB Gateway/TWS
### Delayed Data Only
**Symptom:** Receiving 15-minute delayed data
**Solution:**
1. Subscribe to real-time data for the exchange
2. For paper trading, ensure you have paper trading market data enabled
3. Use `client.switch_market_data_type(MarketDataType::Delayed)` to explicitly request delayed data
## Order Issues
### Invalid Order ID
**Error:**
```
Error: Invalid order ID
```
**Solution:**
Use the canonical fluent path — `submit()` allocates a valid id internally:
```rust
let order_id = client.order(&contract).buy(100).market().submit()?;
```
For BYO-id flows (external allocator) use `client.next_order_id()` and the lower-level `client.submit_order(id, &contract, &order)` / `client.place_order(id, &contract, &order)`.
### Order Rejected
**Error:**
```
Error: Order rejected - reason: ...
```
**Common Reasons:**
1. **Insufficient funds** - Check account balance
2. **Invalid symbol** - Verify contract details
3. **Market closed** - Check trading hours
4. **Invalid order type** - Some order types require specific exchanges
5. **Position limits** - Check account restrictions
## Runtime Issues
### Subscription Ends Immediately
**Symptom:** Market data subscription returns no data and ends
**Solutions:**
1. Check if market is open
2. Verify contract is valid
3. Ensure market data permissions
4. Check for error messages in debug logs
### Missing Messages
**Symptom:** Not receiving expected responses
**Solution:**
Enable debug logging to see all messages:
```bash
RUST_LOG=debug cargo run --no-default-features --features sync --example your_example
```
### Slow Performance
**Solutions:**
1. Use async mode for high-concurrency scenarios
2. Reduce logging level in production
3. Use batch operations where available
4. Check network latency to IB servers
## Debugging Techniques
### Enable Debug Logging
See detailed communication with TWS:
```bash
# Debug level
RUST_LOG=debug cargo run --no-default-features --features sync --example your_example
# Trace level (very verbose)
RUST_LOG=trace cargo run --no-default-features --features sync --example your_example
# Only ibapi debug messages
RUST_LOG=ibapi=debug cargo run --no-default-features --features sync --example your_example
```
### Record TWS Messages
Save all TWS communication for analysis. Each run writes a timestamped
subdirectory holding one file per message, numbered in the order they crossed
the wire:
```bash
IBAPI_RECORDING_DIR=/tmp/tws-messages cargo run --no-default-features --features sync --example your_example
# View recorded messages
ls -la /tmp/tws-messages/*/
xxd /tmp/tws-messages/*/0000-request.msg
```
Responses are recorded **after parsing** and re-framed from the parsed message,
so this is the right tool for "what did TWS say" and the wrong one for "how did
the bytes arrive". For the latter, see below.
### Capture the Raw Wire (framing problems)
**Symptom:** decoded values are wrong in a structured way — one field
consistently off, or garbage that still parses — rather than an error. Or a
`Notice` with code `-5` ("message id … maps to no known type"), or an
`Error::InvalidFrame`. All three point at the *framing*: a length prefix that
does not describe the frame behind it, after which every subsequent read starts
mid-message.
`IBAPI_RECORDING_DIR` cannot diagnose this — it never sees the length prefix,
which is the corrupted field. `IBAPI_RAW_CAPTURE_DIR` taps the socket below the
framing instead:
```bash
IBAPI_RAW_CAPTURE_DIR=/tmp/tws-raw cargo run --example your_example
```
Each connection produces a pair of files (a reconnect starts a new pair):
- `<stamp>-<n>-inbound-<NNN>.bin` — the inbound stream byte for byte, length
prefixes included.
- `<stamp>-<n>-inbound-<NNN>.idx` — `seq,utc_timestamp,offset,declared_length`
per frame, for lining a frame up against timestamps in your own logs.
Walk a capture with the bundled example, which reports the first frame whose
prefix cannot describe a frame and exits non-zero if it finds one:
```bash
cargo run --example replay_raw_capture -- /tmp/tws-raw/*-inbound-000.bin
cargo run --example replay_raw_capture -- --frames /tmp/tws-raw/*-inbound-000.bin # list every frame
```
Captures are unredacted wire bytes: they contain your account ids, positions,
and orders. Treat them like logs of live trading activity before attaching one
to an issue.
### Common Debug Patterns
```rust
// Add debug output to your code
dbg!(&contract);
println!("Order state: {:?}", order_status);
// Use expect for better error messages
let client = Client::connect("127.0.0.1:4002", 100)
.expect("Failed to connect to IB Gateway");
// Handle specific errors
match client.place_order(order_id, &contract, &order) {
Ok(_) => println!("Order placed successfully"),
Err(Error::InvalidOrderId) => println!("Invalid order ID"),
Err(e) => println!("Order failed: {}", e),
}
```
## Testing Issues
### Tests Failing in CI
**Common Causes:**
1. Not testing both feature modes
2. Network-dependent tests without mocking
3. Time-dependent tests
**Solution:**
```bash
# Always test both modes locally before pushing
cargo test
cargo test --no-default-features --features sync
cargo clippy
cargo clippy --no-default-features --features sync
```
## Platform-Specific Issues
### macOS: Security Warnings
**Issue:** macOS blocks IB Gateway from accepting connections
**Solution:**
1. Go to System Preferences → Security & Privacy
2. Allow IB Gateway to accept incoming connections
3. Or run IB Gateway with reduced security (development only)
### Linux: Permission Denied
**Issue:** Cannot bind to port
**Solution:**
1. Run IB Gateway as your user (not root)
2. Ensure port is not already in use: `lsof -i :4002`
3. Check SELinux/AppArmor policies if enabled
### Windows: Firewall Blocking
**Issue:** Windows Firewall blocking connections
**Solution:**
1. Add IB Gateway to firewall exceptions
2. Allow localhost connections
3. Temporarily disable firewall for testing (not recommended for production)
## Getting Further Help
If you're still stuck:
1. **Search existing issues**: [GitHub Issues](https://github.com/wboayue/rust-ibapi/issues)
2. **Check examples**: Most common patterns are demonstrated
3. **Read test cases**: Tests show expected behavior
4. **Enable debug logging**: Often reveals the root cause
5. **Create an issue**: Include:
- Rust version (`rustc --version`)
- Feature flag used (sync or async)
- Minimal code to reproduce
- Full error message
- Debug log output
## Quick Fixes Checklist
- [ ] Building the feature configuration you meant (`--features sync` alone is sync + async)?
- [ ] IB Gateway/TWS running?
- [ ] Correct port number?
- [ ] API enabled in IB Gateway/TWS?
- [ ] Market data subscriptions active?
- [ ] Submitting via `client.order(&contract).…submit()` (canonical) or BYO-id `next_order_id()` + `submit_order` (advanced)?
- [ ] Market open for the symbol?
- [ ] Debug logging enabled?
- [ ] Checked examples for similar use case?
- [ ] Tested both sync and async modes?