{"record":{"id":"9bb0ec1784b64dc1","repo":"unslothai/unsloth","slug":"tensor-split-must-have-a-positive-total","errorCode":null,"errorMessage":"tensor_split must have a positive total","messagePattern":"tensor_split must have a positive total","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"studio/backend/models/inference.py","lineNumber":262,"sourceCode":"        # folding into the int core schema, and they leak into OpenAPI as ge/le.\n        if isinstance(value, bool):\n            raise ValueError(\"Expected a number, got a boolean.\")\n        return value\n\n    @field_validator(\"tensor_split\")\n    @classmethod\n    def _reject_degenerate_tensor_split(cls, value: Optional[List[float]]) -> Optional[List[float]]:\n        # A negative / non-finite / all-zero split is silently dropped at launch\n        # (stored as None) yet still compared raw in the reload dedupe, so an\n        # identical Apply reloads forever. Reject it up front; [] = no split.\n        if not value:\n            return value\n        import math\n\n        if any((not math.isfinite(v)) or v < 0 for v in value):\n            raise ValueError(\"tensor_split entries must be finite and non-negative\")\n        if sum(value) <= 0:\n            raise ValueError(\"tensor_split must have a positive total\")\n        return value\n\n    llama_extra_args: Optional[List[str]] = Field(\n        None,\n        description = (\n            \"Extra arguments forwarded verbatim to llama-server for GGUF models. \"\n            \"One token per list entry, e.g. ['--top-k', '20', '--seed', '42']. \"\n            \"Unsloth-managed flags (model identity, port, context length, GPU placement, \"\n            \"auth, UI/server mode) are rejected. Ignored for non-GGUF models.\"\n        ),\n    )\n    force_cancel_active: bool = Field(\n        False,\n        description = (\n            \"Stop chats still generating instead of refusing with 409. A load \"\n            \"replaces the llama-server every open conversation decodes on.\"\n        ),\n    )","sourceCodeStart":244,"sourceCodeEnd":280,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/models/inference.py#L244-L280","documentation":"Raised by the same tensor_split validator after the per-entry check passes: the sum of all entries must be strictly positive. An all-zero (or all entries summing to 0) list is degenerate — it would be silently dropped at launch yet keep triggering reload-dedupe comparisons, so it is rejected as a 422.","triggerScenarios":"Sending tensor_split: [0, 0] or [0.0, 0.0] (entries pass the finite/non-negative check but total 0). A single positive entry avoids it; [] means 'no split' and is allowed.","commonSituations":"Auto-probing code that builds a split from detected GPUs and finds none, yielding a list of zeros instead of an empty list; placeholder configs shipped with zeros; users trying to 'disable' one GPU with 0 while the other is also 0.","solutions":["If you meant 'no tensor split', send [] or omit tensor_split entirely.","If you meant to disable a GPU, weight the others positively, e.g. [0, 1, 1].","Fix the client's GPU-probing fallback to emit an empty list when no GPUs are detected."],"exampleFix":"# before\npayload = {\"tensor_split\": [0, 0]}\n\n# after\npayload = {\"tensor_split\": []}  # or omit the key entirely","handlingStrategy":"validation","validationCode":"def sanitize_split(split: list[float] | None) -> list[float] | None:\n    if not split or sum(split) <= 0:\n        return None  # normalize degenerate splits to 'no split'\n    return split","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat all-zero GPU splits as 'no GPUs detected' and omit the field","Disable a GPU with weight 0 only alongside at least one positive entry","Unit-test split builders against the empty-GPU case"],"tags":["pydantic","validation","tensor-split","gpu","llama-server"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}