unslothai/unsloth · warning · ValueError
fraction must be a number, not a boolean
Error message
fraction must be a number, not a boolean
What it means
Pydantic validation failure (HTTP 422) from a mode='before' validator on VramBudgetPayload.fraction. Because bool subclasses int in Python, non-strict pydantic parsing would silently coerce JSON true to 1.0 and store the maximum VRAM budget; the validator runs before coercion and rejects any boolean value explicitly. Valid floats must also satisfy ge=VRAM_FRACTION_MIN and le=VRAM_FRACTION_MAX.
Source
Thrown at studio/backend/routes/settings.py:586
# that residency will not fully pin a model larger than this. None means
# unlimited (macOS) or not applicable (Windows).
memlock_limit_bytes: Optional[int] = None
class VramBudgetPayload(BaseModel):
# None clears the stored budget so env/default applies again; it cannot also
# mean "leave untouched" as the model-memory switches do, since there is one
# field. Hence required, not defaulted: with a default, {} would mean "clear it"
# and a client that dropped the field would silently discard the stored budget.
fraction: Optional[float] = Field(ge = VRAM_FRACTION_MIN, le = VRAM_FRACTION_MAX)
@field_validator("fraction", mode = "before")
@classmethod
def _reject_bool(cls, value: object) -> object:
# bool subclasses int, so non-strict parsing turns True into 1.0 and stores
# the max budget instead of 422; pydantic coerces before the util's guard.
if isinstance(value, bool):
raise ValueError("fraction must be a number, not a boolean")
return value
class VramBudgetResponse(BaseModel):
fraction: float
# False when inherited from UNSLOTH_VRAM_FRACTION or the default, so the UI
# knows whether clearing it would change anything.
is_stored: bool
default_fraction: float = VRAM_FRACTION_DEFAULT
min_fraction: float = VRAM_FRACTION_MIN
max_fraction: float = VRAM_FRACTION_MAX
# Read when a load sizes itself, so a change cannot reach a running child.
reload_required: bool
class HuggingFaceCachePayload(BaseModel):
cache_home: Optional[str] = Field(default = None, max_length = 4096)
View on GitHub (pinned to 203007d190)
Solutions
- Send an explicit float within [VRAM_FRACTION_MIN, VRAM_FRACTION_MAX], e.g. 0.8; send null to clear the stored budget.
- Type-check client-side: reject boolean before submitting.
- If you generate payloads from schemas, ensure fraction is a number type, never a bool.
Example fix
// before
await api.put('/settings/vram-budget', { fraction: true }); // 422
// after
if (typeof fraction !== 'number') throw new TypeError('fraction must be a number');
await api.put('/settings/vram-budget', { fraction: 0.8 }); Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof fraction !== 'number' && fraction !== null) {
throw new TypeError('fraction must be a number or null');
}
await api.put('/settings/vram-budget', { fraction }); Type guard
function isVramFraction(v: unknown): v is number {
return typeof v === 'number' && Number.isFinite(v) && v >= 0 && v <= 1;
} Try / catch
try { await api.put('/settings/vram-budget', { fraction }); }
catch (e) {
if (e.status === 422 && /boolean/.test(e.detail?.toString() ?? '')) { fixPayloadType('fraction'); return; }
throw e;
} Prevention
- Never bind a boolean control to numeric settings fields.
- Send null (not 0, not false) to clear the budget.
- Run generated payloads through a JSON schema with type:number.
When it happens
Trigger: PUT the VRAM budget endpoint with fraction: true or false in the JSON body; also any truthy value a client serializes as a JS boolean (e.g. fraction: isMax) instead of the intended number.
Common situations: JS frontend binding a checkbox/toggle state to fraction; YAML/JSON config generated from a template where a number became a boolean; API consumers testing with literal true.
Related errors
- Expected a number, got a boolean.
- Expected numbers, got a boolean.
- Provide either content_base64 or file_ids, not both
- Provide either content_base64 or file_ids
- file_ids must not be empty
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/9f0d4a20fbe3ccc9.
Report an issue: GitHub.