{"record":{"id":"d5e3b04a5eb6fd6b","repo":"Hmbown/CodeWhale","slug":"disabled-tools-must-use-codewhale-catalog-identifiers","errorCode":null,"errorMessage":"disabled_tools must use Codewhale catalog identifiers: {invalid_tools}","messagePattern":"disabled_tools must use Codewhale catalog identifiers: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"integrations/verifiers-codewhale/codewhale_harness/harness.py","lineNumber":110,"sourceCode":"    APPENDS_SYSTEM_PROMPT = True\n    SUPPORTS_MCP = True\n    SUPPORTS_USER_SIM = False\n\n    def _validate_config(self) -> None:\n        if not _VERSION.fullmatch(self.config.version):\n            raise ValueError(\"version must be a semantic release identifier\")\n        if (\n            self.config.max_turns is not None\n            and not 1 <= self.config.max_turns <= 10_000\n        ):\n            raise ValueError(\"max_turns must be between 1 and 10000\")\n        invalid = [\n            tool\n            for tool in self.config.disabled_tools or []\n            if not _TOOL.fullmatch(tool)\n        ]\n        if invalid:\n            raise ValueError(\n                \"disabled_tools must use Codewhale catalog identifiers: \"\n                + \", \".join(repr(tool) for tool in invalid)\n            )\n\n    @property\n    def binary(self) -> str:\n        configured = (self.config.binary_path or \"\").strip()\n        return configured or DEFAULT_BINARY\n\n    async def setup(self, runtime: Runtime) -> None:\n        self._validate_config()\n        if self.config.binary_path:\n            logger.info(\"codewhale: verifying preinstalled %s\", self.binary)\n            result = await runtime.run([self.binary, \"--version\"], {})\n            version_text = f\"{result.stdout}\\n{result.stderr}\"\n            if result.exit_code != 0 or not _has_version(\n                version_text, self.config.version\n            ):","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/integrations/verifiers-codewhale/codewhale_harness/harness.py#L92-L128","documentation":"_validate_config checks every entry of config.disabled_tools against the catalog-identifier regex ^[a-z0-9][a-z0-9_-]*$ and raises listing the offending names. The harness forwards these verbatim as --disallowed-tools to the Codewhale CLI, so names must match the Codewhale tool catalog format.","triggerScenarios":"Passing CodewhaleHarnessConfig(disabled_tools=['Bash', 'web-search!', '']) — any tool name starting with an uppercase letter or symbol, containing spaces/dots/slashes, or empty — then calling setup() or launch(). The message includes the repr of each invalid name.","commonSituations":"Using tool names from a different agent's catalog (e.g. capitalized Claude-style names); typo'd identifiers; accidentally including whitespace or commas from a comma-separated string instead of a list.","solutions":["Rewrite each disabled_tools entry to match ^[a-z0-9][a-z0-9_-]*$ (lowercase letters/digits start, then lowercase, digits, underscore, hyphen)","Check the Codewhale tool catalog for the exact identifier of each tool you want to disable","If the names came from a comma-joined string, split it into a proper list first"],"exampleFix":"// before\nCodewhaleHarnessConfig(disabled_tools=[\"Bash\", \"Web Search\"])\n// after\nCodewhaleHarnessConfig(disabled_tools=[\"bash\", \"web_search\"])","handlingStrategy":"validation","validationCode":"import re\n_TOOL = re.compile(r\"^[a-z0-9][a-z0-9_-]*$\")\nbad = [t for t in cfg.disabled_tools or [] if not _TOOL.fullmatch(t)]\nassert not bad, f\"invalid tool ids: {bad}\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep a list of valid Codewhale catalog identifiers and check membership","Never pass comma-joined strings; always a Python list of ids","Use lowercase snake/kebab-case names"],"tags":["validation","config","naming"],"backgroundTag":"invalid-identifier-format","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}