{"record":{"id":"4bfcacbc50f28c06","repo":"shareAI-lab/learn-claude-code","slug":"block-cap-must-be-at-least-1","errorCode":null,"errorMessage":"block_cap must be at least 1","messagePattern":"block_cap must be at least 1","errorType":"validation","errorClass":"GoalError","httpStatus":null,"severity":"error","filePath":"s17_goal_loop/code.py","lineNumber":271,"sourceCode":"            ),\n            messages=[{\"role\": \"user\", \"content\": prompt}],\n            max_tokens=self.max_tokens,\n        )\n        value = _parse_json_object(_extract_text(response.content))\n        return GoalEvaluation(**value)\n\n\nclass GoalController:\n    \"\"\"Session-scoped goal state plus the Stop hook decision.\"\"\"\n\n    def __init__(\n        self,\n        evaluator: Any,\n        block_cap: int = DEFAULT_STOP_HOOK_BLOCK_CAP,\n        events: list[dict[str, Any]] | None = None,\n    ):\n        if block_cap < 1:\n            raise GoalError(\"block_cap must be at least 1\")\n        self.evaluator = evaluator\n        self.block_cap = block_cap\n        self.events = events if events is not None else []\n        self.active: GoalState | None = None\n        self.last_status: dict[str, Any] | None = None\n        self.consecutive_blocks = 0\n\n    def begin_query(self) -> None:\n        self.consecutive_blocks = 0\n\n    def set_goal(self, condition: str, tokens_at_start: int = 0) -> GoalState:\n        condition = condition.strip()\n        if not condition:\n            raise GoalError(\"goal condition cannot be empty\")\n        if len(condition) > MAX_GOAL_LENGTH:\n            raise GoalError(\n                f\"goal condition cannot exceed {MAX_GOAL_LENGTH} characters\"\n            )","sourceCodeStart":253,"sourceCodeEnd":289,"githubUrl":"https://github.com/shareAI-lab/learn-claude-code/blob/985456f4adea6f4df8fbad4112245dbd97444eae/s17_goal_loop/code.py#L253-L289","documentation":"GoalController was constructed with block_cap < 1. block_cap limits how many times the Stop hook may consecutively block the agent from stopping (DEFAULT_STOP_HOOK_BLOCK_CAP is 8); a cap of 0 or negative would make the loop logic meaningless, so the constructor fails fast (s17_goal_loop/code.py:271).","triggerScenarios":"Directly instantiating GoalController(evaluator, block_cap=0) or block_cap=-3. Indirectly: setting the environment variable CLAUDE_CODE_STOP_HOOK_BLOCK_CAP to 0 or a negative number, which make_live_session converts with int() and passes in.","commonSituations":"Trying to 'disable' the stop-hook blocking by setting the cap to 0 (use a cap of 1 for single-block behavior instead); misreading the env var as a boolean flag; passing a value parsed from user config without validation.","solutions":["Pass block_cap >= 1 (1 means the hook blocks at most once, then lets the agent stop)","If disabling blocking was the intent, do not construct the controller with a hook, or set the cap to 1","Set CLAUDE_CODE_STOP_HOOK_BLOCK_CAP to a positive integer such as 8, or unset it to accept the default"],"exampleFix":"# before\ncontroller = GoalController(evaluator, block_cap=0)\n\n# after\ncontroller = GoalController(evaluator, block_cap=1)","handlingStrategy":"validation","validationCode":"raw_cap = int(os.getenv(\"CLAUDE_CODE_STOP_HOOK_BLOCK_CAP\", 8))\nif raw_cap < 1:\n    raise SystemExit(\"CLAUDE_CODE_STOP_HOOK_BLOCK_CAP must be >= 1\")\ncontroller = GoalController(evaluator, block_cap=raw_cap)","typeGuard":"def is_valid_block_cap(value: object) -> bool:\n    return isinstance(value, int) and not isinstance(value, bool) and value >= 1","tryCatchPattern":"try:\n    GoalController(evaluator, block_cap=cap)\nexcept GoalError:\n    cap = DEFAULT_STOP_HOOK_BLOCK_CAP\n    controller = GoalController(evaluator, block_cap=cap)","preventionTips":["Never use 0 to mean 'disabled' — use 1 for minimal blocking or omit the hook","Validate user-supplied numeric config before constructing the controller","Remember the env var flows through int(); reject negatives at the config boundary"],"tags":["goal-loop","config","validation","constructor"],"backgroundTag":null,"analyzedSha":"985456f4adea6f4df8fbad4112245dbd97444eae","analyzedAt":"2026-08-14T22:02:26.028Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}