{"record":{"id":"690ccc2abd8f817b","repo":"calesthio/OpenMontage","slug":"first-paid-use-of-tool-entry-tool-r-requires","errorCode":null,"errorMessage":"First paid use of tool {entry['tool']!r} requires approval","messagePattern":"First paid use of tool (.+?) requires approval","errorType":"exception","errorClass":"ApprovalRequiredError","httpStatus":null,"severity":"warning","filePath":"tools/cost_tracker.py","lineNumber":138,"sourceCode":"        Raises BudgetExceededError in cap mode, or ApprovalRequiredError\n        when the action exceeds the single-action approval threshold.\n        \"\"\"\n        entry = self._find(entry_id)\n        estimated = entry[\"estimated_usd\"]\n\n        # Check single-action approval threshold\n        if estimated > self.single_action_approval_usd:\n            if self.mode != BudgetMode.OBSERVE:\n                raise ApprovalRequiredError(\n                    f\"Action costs ${estimated:.2f}, exceeds \"\n                    f\"single-action threshold ${self.single_action_approval_usd:.2f}\"\n                )\n\n        # Check new paid tool approval\n        if self.require_approval_for_new_paid_tool and estimated > 0:\n            if entry[\"tool\"] not in self._approved_tools:\n                if self.mode != BudgetMode.OBSERVE:\n                    raise ApprovalRequiredError(\n                        f\"First paid use of tool {entry['tool']!r} requires approval\"\n                    )\n\n        # Check budget\n        if estimated > self.usable_budget_usd:\n            message = (\n                f\"Reservation of ${estimated:.2f} exceeds usable budget \"\n                f\"${self.usable_budget_usd:.2f}\"\n            )\n            if self.mode == BudgetMode.CAP:\n                raise BudgetExceededError(message)\n            if self.mode == BudgetMode.WARN:\n                entry[\"budget_warning\"] = True\n                entry[\"budget_warning_message\"] = message\n\n        entry[\"status\"] = EntryStatus.RESERVED.value\n        entry[\"reserved_usd\"] = estimated\n        entry[\"timestamp\"] = self._now()","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/calesthio/OpenMontage/blob/95e1c3d0ab93482159818560f6a8c8e866b9139f/tools/cost_tracker.py#L120-L156","documentation":"ApprovalRequiredError raised by CostTracker.reserve when require_approval_for_new_paid_tool is enabled, the entry has estimated_usd > 0, and the tool name is not in _approved_tools. It enforces an explicit opt-in the first time any paid tool is used, independent of amount. Once approve_tool(tool) is called the name is persisted in approved_tools and later reserves succeed.","triggerScenarios":"reserve() on the first paid entry for a tool with require_approval_for_new_paid_tool=True and mode != OBSERVE. Every new provider/tool (new image model, new TTS engine) triggers it once until approved.","commonSituations":"Fresh projects or fresh cost logs where approved_tools is empty; adding a new tool to a workflow after initial setup; loading an old cost log that predates the tool.","solutions":["Approve the tool once via tracker.approve_tool(entry['tool']) (it persists to the cost log) and retry reserve().","Pre-populate approved_tools in the budget/cost-log config for tools you know are sanctioned.","Disable require_approval_for_new_paid_tool if per-tool gating is not wanted.","Run in OBSERVE mode for exploratory sessions where approvals should not block."],"exampleFix":"# before\ntracker.reserve(entry_id)  # first paid use of 'kling_tts' -> ApprovalRequiredError\n\n# after\nif entry[\"tool\"] not in tracker._approved_tools:\n    tracker.approve_tool(entry[\"tool\"])\ntracker.reserve(entry_id)","handlingStrategy":"validation","validationCode":"def tool_approved(tracker, tool: str) -> bool:\n    return tool in tracker._approved_tools","typeGuard":null,"tryCatchPattern":"from tools.cost_tracker import ApprovalRequiredError\n\ntry:\n    tracker.reserve(entry_id)\nexcept ApprovalRequiredError as e:\n    if \"requires approval\" in str(e):\n        tracker.approve_tool(tool_name)\n        tracker.reserve(entry_id)","preventionTips":["Pre-approve known-good tools right after tracker initialization.","Persist the cost log so approved_tools survives restarts.","Wrap reserve() in a helper that auto-handles first-use approval if policy allows."],"tags":["budget","cost-tracking","approval","policy"],"backgroundTag":null,"analyzedSha":"95e1c3d0ab93482159818560f6a8c8e866b9139f","analyzedAt":"2026-08-15T06:31:20.014Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}