HKUDS/Vibe-Trading · error · UsdMObservationError

Binance USD-M field {name} must be an integer

Error message

Binance USD-M field {name} must be an integer

What it means

Raised by _integer when a field is numeric and non-negative but has a fractional part (number.is_integer() is False). Used for fields that must be whole numbers, such as counts, indices, or update timestamps passed through _join_positions. The {name} placeholder names the offending field.

Source

Thrown at agent/src/trading/connectors/binance/usdm.py:338

    positive: bool = False,
) -> float:
    try:
        number = float(value)
    except (TypeError, ValueError) as exc:
        raise UsdMObservationError(f"Binance USD-M field {name} must be numeric") from exc
    if not math.isfinite(number):
        raise UsdMObservationError(f"Binance USD-M field {name} must be finite")
    if positive and number <= 0:
        raise UsdMObservationError(f"Binance USD-M field {name} must be positive")
    if non_negative and number < 0:
        raise UsdMObservationError(f"Binance USD-M field {name} must be non-negative")
    return number


def _integer(value: Any, name: str) -> int:
    number = _number(value, name, non_negative=True)
    if not number.is_integer():
        raise UsdMObservationError(f"Binance USD-M field {name} must be an integer")
    return int(number)


def _configuration_hash(source_profile: str, host: str, absolute_tolerance: float) -> str:
    payload = {
        "schema_version": SCHEMA_VERSION,
        "source_profile": source_profile,
        "market_type": "usdm",
        "host": host,
        "account_endpoint": "/fapi/v2/account",
        "position_endpoint": "/fapi/v3/positionRisk",
        "observation_absolute_tolerance": absolute_tolerance,
        "observation_relative_tolerance": OBSERVATION_RELATIVE_TOLERANCE,
    }
    encoded = json.dumps(payload, sort_keys=True, separators=(",", ":")).encode()
    return hashlib.sha256(encoded).hexdigest()

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Check the named field in the raw payload for fractional values
  2. Fix the producer: compute integer fields with integer arithmetic (// or round) or fix the fixture
  3. Convert legitimately float-typed integral values (e.g. '3.0') before passing if the source is string-float
  4. Verify field mapping — a fractional value often means the wrong field is being read

Example fix

// before
_integer(payload.get("count"), "count")  # 2.5
// after
_integer(round(payload["count"]), "count")  # or fix fixture to 2
Defensive patterns

Strategy: validation

Validate before calling

def as_int(v) -> int | None:
    try:
        f = float(v)
    except (TypeError, ValueError):
        return None
    return int(f) if f.is_integer() else None

payload["count"] = as_int(payload.get("count")) or 0

Type guard

def is_integer_valued(value: Any) -> TypeGuard[int]:
    try:
        return float(value).is_integer()
    except (TypeError, ValueError):
        return False

Try / catch

try:
    obs = connector.read_account_observation(...)
except UsdMObservationError as exc:
    if "must be an integer" in str(exc):
        logger.error("fractional value in integer field: %s", exc)
        fix_producer_and_refetch()
    raise

Prevention

When it happens

Trigger: A field expected to be an integer holds e.g. 1.5 or '3.0' is fine but '2.7' fails; commonly a float-scaled value (price*qty) accidentally placed where a count/index was expected, or mock data using arbitrary floats.

Common situations: Fixtures using random floats for integer fields; upstream computing an integer field via floating division; API change adding decimal precision to a previously integral field; unit confusion (ticks vs contracts).

Related errors


AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28). Data as JSON: /api/errors/e4dbd559ac1a45cf. Report an issue: GitHub.