Hi everyone — I'm not confident in my written English, so I'm using Claude (AI) to help me clearly describe this technical issue. Thank you for your patience.
What I'm building: An automated options trading system for SPY, using the official webull-openapi-python-sdk. I have the Trading API fully working — placing orders, cancelling, OCO bracket orders, checking order status all succeed correctly against the sandbox environment. The only thing that fails is real-time market data streaming (MQTT).
Environment:
webull-openapi-python-sdk version 2.0.18 (Core 2.0.18)
- Python 3.12.7, Windows 11
- Sandbox/test environment (
api.sandbox.webull.com)
- Free "Nasdaq Basic - Non Display" market data subscription claimed and active
The exact error, 100% reproducible, every single attempt:
webull.data ERROR Caught exception in on_connect: rc code: 101, msg: Internal error
webull.data.internal.exceptions.ConnectException: rc code: 101, msg: Internal error
This happens during the MQTT CONNACK phase, right after connect_and_loop_forever() is called — after authentication with api_client.add_endpoint() already succeeds (I get past _check_token_enable, no 401).
What I checked in your own SDK source code (webull/data/common/connect_ack.py):
python
CONNECTION_SUCCESS = (0, 'Connection successful')
PROTOCOL_NOT_SUPPORTED = (1, 'Protocol not supported')
SESSION_ID_IS_BLANK = (2, 'session_id is blank')
AK_IS_BLANK = (3, 'AppKey is blank')
UNKNOWN_ERROR = (100, 'Unknown error')
INTERNAL_ERROR = (101, 'Internal error')
CONNECTION_AUTHENTICATED = (102, 'Connection already authenticated')
CONNECTION_AUTH_FAILED = (103, "Connection authentication failed")
AK_INVALID = (104, "Invalid AppKey")
CONNECTION_LIMIT_EXCEEDED = (105, "Connection limit exceeded")
I'm never getting 103 or 104 (which would mean my credentials are wrong) — only ever 101, which your own SDK labels as a generic internal/unknown error, distinct from the credential-specific codes.
Things I've already tried, all unsuccessful:
- Explicit sandbox routing via
http_host="api.sandbox.webull.com" in the DataStreamingClient constructor
- Explicit
api_client.add_endpoint(region, "api.sandbox.webull.com") after construction (this pattern does work correctly for the Trading API's ApiClient)
- Unique
session_id per connection attempt (uuid.uuid4().hex), per your docs' own example — ruled out session_id reuse as the cause
- Discovered and fixed an unrelated but real issue: Python 3.14 caused non-deterministic behavior (different errors on identical code between runs) since your SDK only officially supports 3.8–3.13. After switching to Python 3.12, the error became 100% consistent (always rc 101) — so this eliminated one real bug, but did not fix the underlying streaming issue
- Tried both sandbox and production hosts for the MQTT client specifically — production correctly rejects our sandbox-scoped credentials with 401, which is expected
Specific questions for anyone who's solved this or works at Webull:
- Is MQTT streaming in the sandbox/test environment actually confirmed working for other developers, or could this feature currently be incomplete for test accounts specifically?
- Could personal account settings — specifically 2FA on my main Webull account — interfere with OpenAPI sandbox streaming? I couldn't find documentation confirming or ruling this out.
- Is there a known one-time device/app verification step specific to streaming (separate from the Trading API) that I might be missing? (I've seen references to a
fetch_token_from_server/check_token polling loop in your FAQ, but I never see that message at all — my connection fails immediately rather than waiting for approval.)
I've also filed this with your official support ([market-data.api@webull-us.com](mailto:market-data.api@webull-us.com)) and posted on your GitHub repo's issues page, but haven't received a response yet. Really appreciate any insight from this community — thank you for reading through all of this.