[Bug] Response models declare numeric fields as strict `str`, causing silent fallback of `.data()` to raw dict (simple-earn & staking)
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Idoneità per principianti
- 68/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Attiva
- Stack tecnologico
- python
- Ambito
- api, backend-api-design
Direzione di ricerca
Inizia riproducendo gli esempi di model_validate nell'issue. Esamina i modelli indicati in binance-sdk-simple-earn/rest_api/models e binance-sdk-staking/rest_api/models, quindi leggi binance_common.utils.send_request per comprendere il fallback ai dizionari grezzi. Il lavoro è completato quando i payload numerici con forma di produzione restituiscono costantemente oggetti modello e il comportamento di fallback viene gestito come previsto.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
[Bug] Response models declare numeric fields as strict str, causing silent fallback of .data() to raw dict (simple-earn & staking)
Environment
binance-sdk-simple-earn8.0.0binance-sdk-staking5.11.0binance-common4.0.0- Python 3.14.6, Windows 11
Summary
Several REST response models declare fields as StrictStr while the live API returns JSON numbers for them. Pydantic strict validation therefore fails on every real response, and binance_common.utils.send_request silently falls back to returning the raw parsed JSON. As a result, ApiResponse.data() returns a plain dict instead of the documented model object for these endpoints — data.to_dict() / attribute access then raises AttributeError in user code, with no warning that validation failed.
All cases below were reproduced against the production API with real responses on 2026-07-07/08.
Case 1 (verified): SubscribeLockedProductResponse.position_id
POST /sapi/v1/simple-earn/locked/subscribe returns positionId as a number, but the model declares it as strict str.
from binance_sdk_simple_earn.rest_api.models.subscribe_locked_product_response import SubscribeLockedProductResponse
# actual live response of a successful subscription
payload = {'purchaseId': 351129167, 'positionId': 347608223, 'success': True, 'amount': '0.05'}
SubscribeLockedProductResponse.model_validate(payload)
1 validation error for SubscribeLockedProductResponse
positionId
Input should be a valid string [type=string_type, input_value=347608223, input_type=int]
Note: purchase_id is declared StrictInt in the same model, so the numeric purchaseId passes while the numeric positionId fails — the declarations are inconsistent within one model.
Case 2 (verified): GetLockedProductPositionResponse rows
GET /sapi/v1/simple-earn/locked/position rows contain numeric duration, accrualDays, payPeriod, redeemPeriod, but the rows-inner model declares them as strict str.
from binance_sdk_simple_earn.rest_api.models.get_locked_product_position_response import GetLockedProductPositionResponse
# actual live response row of a held position
row = {'positionId': 347608038, 'projectId': 'Bnb*120', 'asset': 'BNB', 'amount': '0.05',
'purchaseTime': 1783439066000, 'duration': 120, 'accrualDays': 0, 'rewardAsset': 'BNB',
'rewardAmt': '0', 'nextPay': '0.00000054', 'nextPayDate': 1783555200000, 'payPeriod': 1,
'redeemAmountEarly': '0.05', 'rewardsEndDate': 1793836800000, 'deliverDate': 1793959200000,
'redeemPeriod': 1, 'canRedeemEarly': True, 'canFastRedemption': True, 'autoSubscribe': False,
'type': 'NORMAL', 'status': 'HOLDING', 'canReStake': False, 'redeemTo': 'SPOT',
'totalBoostRewardAmt': '0', 'apy': '0.004'}
GetLockedProductPositionResponse.model_validate({'rows': [row], 'total': 1})
4 validation errors for GetLockedProductPositionResponse
rows.0.duration Input should be a valid string [input_value=120, input_type=int]
rows.0.accrualDays Input should be a valid string [input_value=0, input_type=int]
rows.0.payPeriod Input should be a valid string [input_value=1, input_type=int]
rows.0.redeemPeriod Input should be a valid string [input_value=1, input_type=int]
Important detail: with an empty rows the wrapper model validates fine, so the endpoint appears healthy until the account actually holds a position — then every call degrades to a raw dict.
Case 3 (same pattern, static): SubscribeOnChainYieldsLockedProductResponse.position_id
binance-sdk-staking, POST /sapi/v1/onchain-yields/locked/subscribe — the model declares:
purchase_id: StrictInt | None
position_id: StrictStr | None <-- same inconsistency as Case 1
The twin Simple Earn endpoint empirically returns positionId as a number (Case 1), and the official docs example for this endpoint also shows a numeric positionId.
Case 4 (same pattern, static): GetOnChainYieldsLockedProductPositionResponseRowsInner
Every field of the rows-inner model is declared strict str, including ones that are numbers on the wire for the twin locked endpoint (Case 2): purchase_time, duration, accrual_days, pay_period, next_pay_date, rewards_end_date, deliver_date, ...
Impact
ApiResponse.data()type is inconsistent per endpoint (model vs raw dict), and the switch is silent — user code calling.to_dict()or accessing attributes crashes withAttributeError.- Particularly nasty on the subscribe endpoint: the subscription has already executed server-side, then response parsing fails client-side, which looks like a failed request.
Suggested fix
- Align model field types with the actual wire types (
intforpositionId,duration, timestamps, etc.), or relaxStrictto allow coercion. - Independently of the type fixes: consider logging a warning in
binance_common.utils.send_requestwhen model validation fails and the raw payload is returned, so the fallback is observable.
- Lingua principale
- Python
- Stelle
- 2.9k
- Fork
- 699
- Metriche di merge delle PR
- Nessuna PR unita negli ultimi 30g
Guida per i contributori
Nessuna guida per i contributori indicizzata per questo repository
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di binance/binance-connector-python
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
binance/binance-connector-python#514 · 1 commento ·
-
Answered
Difficoltà 2/5 1-3 ore Idoneità per principianti 64/100
binance/binance-connector-python#502 · 3 commenti ·
-
Answered
Difficoltà 3/5 1-2 giorni Idoneità per principianti 68/100
binance/binance-connector-python#513 · 2 commenti ·
-
Answered
Difficoltà 2/5 1-3 ore Idoneità per principianti 56/100
binance/binance-connector-python#512 · 1 commento ·
-
Difficoltà 5/5 Più di una settimana Idoneità per principianti 20/100
Tutte le issue di binance/binance-connector-python
Issue simili
-
agent-ready documentation needs-triage
Difficoltà 1/5 1-3 ore Idoneità per principianti 88/100
-
documentation
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 91/100
-
workflow-status page template still says reusable workflows are "triggered only by workflow_call:" Aperta
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 92/100
-
instance instance add
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 72/100
searxng/searx-instances#939 · 1 commento ·
-
area-deployment area-integrations triage:bot-seen
Difficoltà 2/5 Mezza giornata Idoneità per principianti 86/100