{"record":{"id":"119eb0c4851dbd45","repo":"Graphify-Labs/graphify","slug":"token-budget-must-be-positive-got-token-budget","errorCode":null,"errorMessage":"token_budget must be positive, got {token_budget}","messagePattern":"token_budget must be positive, got (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"graphify/llm.py","lineNumber":1920,"sourceCode":"    return len(_TOKENIZER.encode(content, disallowed_special=())) + (_PER_FILE_OVERHEAD_CHARS // _CHARS_PER_TOKEN)\n\n\ndef _pack_chunks_by_tokens(\n    files: \"list[Path | FileSlice]\",\n    token_budget: int,\n) -> \"list[list[Path | FileSlice]]\":\n    \"\"\"Greedily pack files/slices into chunks that fit a token budget.\n\n    Units are first grouped by parent directory so related artifacts share a\n    chunk (cross-file edges are more likely to be extracted within a chunk\n    than across chunks). Within each directory, units are added one at a\n    time; a chunk is closed when adding the next would exceed the budget.\n    Oversized splittable documents are pre-split into ``FileSlice`` units by\n    ``expand_oversized_files`` before packing (#1369), so the old \"one file\n    larger than the budget\" case no longer silently drops content.\n    \"\"\"\n    if token_budget <= 0:\n        raise ValueError(f\"token_budget must be positive, got {token_budget}\")\n\n    by_dir: dict[Path, \"list[Path | FileSlice]\"] = {}\n    for f in files:\n        by_dir.setdefault(unit_path(f).parent, []).append(f)\n\n    chunks: \"list[list[Path | FileSlice]]\" = []\n    current: \"list[Path | FileSlice]\" = []\n    current_tokens = 0\n    current_images = 0\n\n    for directory in sorted(by_dir):\n        for unit in by_dir[directory]:\n            cost = _estimate_file_tokens(unit)\n            is_image = not isinstance(unit, FileSlice) and _is_vision_image(unit)\n            over_budget = current_tokens + cost > token_budget\n            over_images = is_image and current_images >= _MAX_IMAGES_PER_CHUNK\n            if current and (over_budget or over_images):\n                chunks.append(current)","sourceCodeStart":1902,"sourceCodeEnd":1938,"githubUrl":"https://github.com/Graphify-Labs/graphify/blob/7fe58b0b0f3873be9a21c30106b8b8527c353aa6/graphify/llm.py#L1902-L1938","documentation":"Raised at the top of the chunk-packing helper (`pack_files_by_token_budget`-style function) when `token_budget <= 0`. The greedy packer needs a positive budget to decide when a chunk is full; zero or negative would create an infinite-loop/empty-chunk situation, so it fails fast with the offending value in the message.","triggerScenarios":"Passing `token_budget=0` (e.g. from an unset CLI flag defaulting to 0), a negative value, or a computed budget that underflowed (e.g. `max(0, ctx - overhead)` where overhead ≥ ctx).","commonSituations":"CLI wrappers that map `--token-budget` to `int(os.environ.get(\"TOKEN_BUDGET\", 0))`; arithmetic deriving the budget from num_ctx minus a fixed overhead that exceeds small contexts; config files with a missing key defaulting to 0.","solutions":["Pass a positive budget appropriate to the model context, e.g. `token_budget=8192` (well under num_ctx).","If computing the budget, clamp with a sane floor: `max(1024, num_ctx // 3)` as the code's own ollama hint suggests.","Fix the upstream flag/env default that yields 0."],"exampleFix":"# before\nbudget = int(os.environ.get(\"GRAPHIFY_TOKEN_BUDGET\", 0))\n\n# after\nbudget = int(os.environ.get(\"GRAPHIFY_TOKEN_BUDGET\", \"8192\"))","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"def is_valid_token_budget(v: object) -> bool:\n    \"\"\"True for positive integers usable as a chunk token budget.\"\"\"\n    return isinstance(v, int) and not isinstance(v, bool) and v > 0\n\nassert is_valid_token_budget(budget), f\"bad token_budget: {budget!r}\"","tryCatchPattern":null,"preventionTips":["Clamp computed budgets to a floor: `max(1024, num_ctx // 3)`.","Give CLI/env fallbacks a positive default (e.g. 8192), never 0.","Validate config-derived budgets before the packing stage so failure names the bad value."],"tags":["validation","configuration","chunking","token-budget"],"backgroundTag":null,"analyzedSha":"7fe58b0b0f3873be9a21c30106b8b8527c353aa6","analyzedAt":"2026-08-14T19:23:21.323Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}