{"record":{"id":"1390bded0bc93c7a","repo":"huggingface/transformers","slug":"no-real-solution-discriminant","errorCode":null,"errorMessage":"No real solution (discriminant = {})","messagePattern":"No real solution \\(discriminant = (.+?)\\)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"critical","filePath":"src/transformers/generation/continuous_batching/cache.py","lineNumber":747,"sourceCode":"\n    def _check_footprint(self, max_batch_tokens: int, num_blocks: int) -> tuple[int, int]:\n        \"\"\"Checks if the footprint of the cache is within the available memory.\"\"\"\n        memory_footprint = self.compute_memory_footprint(max_batch_tokens, num_blocks)\n        if memory_footprint > self.available_memory:\n            raise MemoryError(\n                f\"Memory footprint {memory_footprint} is more than available memory {self.available_memory}\"\n            )\n        if max_batch_tokens <= 0 or num_blocks <= 0:\n            raise ValueError(f\"Invalid values: max_batch_tokens = {max_batch_tokens}, num_blocks = {num_blocks}\")\n        return max_batch_tokens, num_blocks\n\n    def _solve_quadratic(self, a: float, b: float, c: float) -> int:\n        \"\"\"Largest positive root of a·x² + b·x + c = 0. Falls back to linear when a == 0. Rounded down.\"\"\"\n        if a == 0:\n            return int(-c / b)\n        discriminant = b**2 - 4 * a * c\n        if discriminant < 0:\n            raise ValueError(f\"No real solution (discriminant = {discriminant})\")\n        root = (-b + sqrt(discriminant)) / (2 * a)\n        if root < 0:\n            raise ValueError(f\"No positive solution (root = {root})\")\n        return int(floor(root))\n\n    # Formatting is disabled because of comment indentation, which improves readability.\n    # fmt: off\n    def _equation_coefficients(self, peak_deltas: tuple[int, ...]) -> tuple[int, ...]:\n        \"\"\"Given some deltas corresponding to an activation peak, returns the coefficients for the memory polynomial of\n        that peak. The memory polynomial is described in that class docstring.\"\"\"\n        delta_m, delta_n, delta_mm, delta_mn = peak_deltas\n\n        i = torch.int32.itemsize             # size of int32 in bytes, used for index, input_ids, ...\n        a = self.activation_dtype.itemsize             # for now, the cache and the activation have the same dtype\n        c = self.cache_dtype.itemsize\n        k = self.io_multiplier               # 1 sync, 2 async (IO tensors only)\n\n        # -- N terms: cost per cache page --------------------------------------------------","sourceCodeStart":729,"sourceCodeEnd":765,"githubUrl":"https://github.com/huggingface/transformers/blob/a597f974857b3d92939971296bc0deb93d33d780/src/transformers/generation/continuous_batching/cache.py#L729-L765","documentation":"Raised by PagedAttentionCache._solve_quadratic when the discriminant of the memory-polynomial quadratic is negative, i.e. the equation a·x²+b·x+c=0 has no real root. In practice this means the memory constraint curve never crosses zero, so no batch size can satisfy it — the budget is mathematically unreachable for the given coefficients (e.g. constant memory cost alone exceeds available memory while the quadratic terms grow).","triggerScenarios":"Solving for max_batch_tokens given num_blocks (N given branch) or auto-sizing both via cache_fill_per_batch, when available_memory is smaller than the constant term of the polynomial (cn·N - avail makes c so negative/positive that no real root exists).","commonSituations":"Very small GPU or near-zero available_memory; num_blocks set so large that even zero max_batch_tokens overshoots memory; incorrect activation_peak coefficients for an exotic architecture.","solutions":["Reduce num_blocks (if you set it explicitly) so the fixed cache cost fits available memory","Free memory / use a smaller or quantized model to raise available_memory","Use a smaller cache dtype to shrink the N-dependent coefficient","Let the cache auto-size by passing None for both values with a sane cache_fill_per_batch instead of forcing one variable"],"exampleFix":"# before\ncfg = ContinuousBatchingConfig(num_blocks=4096)  # fixed KV cost alone > available_memory\n\n# after\ncfg = ContinuousBatchingConfig(num_blocks=512)","handlingStrategy":"validation","validationCode":"import torch\nfree_b, _ = torch.cuda.mem_get_info()\n# rough KV bytes per block: 2 (k,v) * layers * block_size * kv_heads * head_dim * dtype_size\nkv_per_block = 2 * num_layers * block_size * num_kv_heads * head_dim * 2\nif cfg.num_blocks is not None and cfg.num_blocks * kv_per_block > free_b:\n    cfg.num_blocks = int(free_b * 0.8 // kv_per_block)","typeGuard":null,"tryCatchPattern":"try:\n    manager = model.continuous_batching(config=cfg)\nexcept ValueError as e:\n    if 'No real solution' in str(e) and cfg.num_blocks:\n        cfg.num_blocks //= 2\n        manager = model.continuous_batching(config=cfg)\n    else:\n        raise","preventionTips":["Estimate KV bytes per block before setting num_blocks","Leave 10-20% headroom on available memory","Prefer auto-sizing (both values None) on unknown hardware"],"tags":["memory","solver","continuous-batching","math"],"backgroundTag":null,"analyzedSha":"a597f974857b3d92939971296bc0deb93d33d780","analyzedAt":"2026-08-14T18:24:08.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}