{"record":{"id":"687e36f648c82c65","repo":"crewAIInc/crewAI","slug":"action-replace-requires-pattern","errorCode":null,"errorMessage":"action='replace' requires 'pattern'.","messagePattern":"action='replace' requires 'pattern'\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"lib/crewai-tools/src/crewai_tools/tools/daytona_sandbox_tool/daytona_file_tool.py","lineNumber":212,"sourceCode":"        if self.action == \"move\" and not self.destination:\n            raise ValueError(\"action='move' requires 'destination'.\")\n        if self.action == \"find\" and not self.pattern:\n            raise ValueError(\n                \"action='find' requires 'pattern' (text to search for inside files).\"\n            )\n        if self.action == \"search\" and not self.pattern:\n            raise ValueError(\"action='search' requires 'pattern' (glob, e.g. '*.py').\")\n        if self.action == \"chmod\" and not (self.mode or self.owner or self.group):\n            raise ValueError(\n                \"action='chmod' requires at least one of 'mode', 'owner', or 'group'.\"\n            )\n        if self.action == \"replace\":\n            if not self.paths:\n                raise ValueError(\n                    \"action='replace' requires 'paths' (list of file paths).\"\n                )\n            if not self.pattern:\n                raise ValueError(\"action='replace' requires 'pattern'.\")\n            if self.replacement is None:\n                raise ValueError(\"action='replace' requires 'replacement'.\")\n        return self\n\n\nclass DaytonaFileTool(DaytonaBaseTool):\n    \"\"\"Read, write, and manage files inside a Daytona sandbox.\n\n    Notes:\n      - Most useful with `persistent=True` or an explicit `sandbox_id`. With the\n        default ephemeral mode, files disappear when this tool call finishes.\n    \"\"\"\n\n    name: str = \"Daytona Sandbox Files\"\n    description: str = (\n        \"Perform filesystem operations inside a Daytona sandbox: read, \"\n        \"write, append, list, delete, mkdir, info, exists, move, find \"\n        \"(content grep), search (filename glob), chmod (permissions/owner/\"","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/crewAIInc/crewAI/blob/754d7323beb2fd042e33444a115ea2d5a47193f0/lib/crewai-tools/src/crewai_tools/tools/daytona_sandbox_tool/daytona_file_tool.py#L194-L230","documentation":"Within the action='replace' branch of DaytonaFileToolSchema._validate_action_args, after paths is confirmed present, a non-empty pattern (the text to find) is required. Omitting pattern or passing an empty string raises this ValueError.","triggerScenarios":"Calling DaytonaFileTool with action='replace', paths and replacement set, but pattern missing/empty; caller swapping pattern and replacement arguments.","commonSituations":"Agent omits the search term; empty pattern from variable interpolation; swapped arguments so pattern receives the new text and the check on the real pattern is bypassed by a similar-looking value.","solutions":["Pass the text to find: tool.run(action='replace', paths=[...], pattern='old_name', replacement='new_name').","Verify pattern (what to find) vs replacement (what to write) are in the right fields.","Assert pattern is a non-empty string before the call."],"exampleFix":"# before\ntool.run(action=\"replace\", paths=[\"/workspace/a.py\"], replacement=\"bar\")  # ValueError\n\n# after\ntool.run(action=\"replace\", paths=[\"/workspace/a.py\"], pattern=\"foo\", replacement=\"bar\")","handlingStrategy":"validation","validationCode":"def validate_replace_pattern(pattern: str | None) -> str:\n    if not pattern:\n        raise ValueError(\"replace requires a non-empty pattern to match\")\n    return pattern","typeGuard":null,"tryCatchPattern":"try:\n    tool.run(action=\"replace\", paths=ps, pattern=pat, replacement=rep)\nexcept ValidationError as e:\n    if \"requires 'pattern'\" in str(e):\n        raise ValueError(\"No search term supplied for bulk replace; refusing to run\") from e\n    raise","preventionTips":["Keep pattern and replacement as a named tuple/pair so they are always set together.","Never run bulk replace with an unbounded or empty pattern.","Log the (pattern, replacement) pair before executing for auditability."],"tags":["daytona","pydantic","validation","input-validation","filesystem"],"backgroundTag":null,"analyzedSha":"754d7323beb2fd042e33444a115ea2d5a47193f0","analyzedAt":"2026-08-15T04:06:56.746Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}