{"record":{"id":"afdb35e55b1d223a","repo":"oraios/serena","slug":"e-class-name-e","errorCode":null,"errorMessage":"{e.__class__.__name__}: {e}","messagePattern":"\\{e\\.__class__\\.__name__\\}: \\{e\\}","errorType":"exception","errorClass":"ToolCallError","httpStatus":null,"severity":"error","filePath":"src/serena/tools/tools_base.py","lineNumber":407,"sourceCode":"                            self.agent.get_language_server_manager_or_raise().restart_language_server(affected_language)\n                            result = apply_fn(**apply_kwargs)\n                        else:\n                            log.error(\n                                f\"Language server terminated while executing tool ({e}), but affected language is unknown. Not retrying.\"\n                            )\n                            raise\n                    else:\n                        raise\n\n                # record tool usage\n                self.agent.record_tool_usage(apply_kwargs, result, self)\n\n            except ToolCallError:\n                raise\n            except Exception as e:\n                msg = f\"{e.__class__.__name__}: {e}\"\n                log.error(msg, exc_info=e)\n                raise ToolCallError(msg)\n\n            if log_call:\n                log.info(f\"Result: {result}\")\n\n            try:\n                ls_manager = self.agent.get_language_server_manager()\n                if ls_manager is not None:\n                    ls_manager.save_all_caches()\n            except Exception as e:\n                log.error(f\"Error saving language server cache: {e}\")\n\n            return result\n\n        # execute the tool in the agent's task executor, with timeout\n        # (task timeout bounds task execution in the dispatcher once it runs, result timeout limits the time we wait)\n        tool_call_error: ToolCallError\n        timeout = self.agent.serena_config.tool_timeout\n        try:","sourceCodeStart":389,"sourceCodeEnd":425,"githubUrl":"https://github.com/oraios/serena/blob/7fcbca7e62555ec2287ddb2f083caee805848ea6/src/serena/tools/tools_base.py#L389-L425","documentation":"The tool-dispatch wrapper task() catches any exception from apply() that is not already a ToolCallError, logs it, and re-raises it as ToolCallError with the message '<ExceptionClass>: <original message>'. This normalizes all unexpected tool failures into a single error type surfaced to the agent/client.","triggerScenarios":"Any unhandled exception inside a tool's apply() — e.g. the ValueErrors/FileNotFoundError above, encoding errors, network/LSP failures — bubbles up through task() and is wrapped.","commonSituations":"Debugging why a tool call failed: the visible ToolCallError is a wrapper; the log (log.error with exc_info) holds the original traceback; wrapping can double-prefix messages on nested task() calls.","solutions":["Read the original exception class and message from the ToolCallError text and fix the underlying cause","Check serena's logs for the full traceback (logged with exc_info)","Catch ToolCallError at the call site and inspect its message to branch on root causes"],"exampleFix":"// before\ntry:\n    tool.apply(...)\nexcept FileNotFoundError:  # never reached — already wrapped\n    ...\n\n// after\ntry:\n    tool.apply(...)\nexcept ToolCallError as e:\n    if 'FileNotFoundError' in str(e):\n        fix_path_and_retry()\n    else:\n        raise","handlingStrategy":"try-catch","validationCode":"# no pre-call check possible; this is the dispatcher's catch-all wrapper.\n# Validate inputs of the underlying apply() yourself:\nassert (Path(project_root) / relative_path).exists(), 'bad path'\nassert max_answer_chars == -1 or max_answer_chars > 0","typeGuard":null,"tryCatchPattern":"try:\n    result = tool.apply(...)\nexcept ToolCallError as e:\n    original_class, _, original_msg = str(e).partition(': ')\n    log.warning('tool failed: %s %s', original_class, original_msg)\n    handle(original_class, original_msg)","preventionTips":["Always catch ToolCallError, not the original exception types — they are wrapped","Read logs for the full original traceback (logged with exc_info)","Parse the '<Class>: <msg>' prefix to branch on root causes","Validate tool arguments yourself before calling apply() to avoid the wrapper entirely"],"tags":["python","error-handling","wrapping","serena"],"backgroundTag":"wrapped-exception","analyzedSha":"7fcbca7e62555ec2287ddb2f083caee805848ea6","analyzedAt":"2026-08-29T00:04:09.619Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}