{"record":{"id":"4c64d654ab5b5899","repo":"crewAIInc/crewAI","slug":"action-chmod-requires-at-least-one-of-mode-o","errorCode":null,"errorMessage":"action='chmod' requires at least one of 'mode', 'owner', or 'group'.","messagePattern":"action='chmod' requires at least one of 'mode', 'owner', or 'group'\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"lib/crewai-tools/src/crewai_tools/tools/daytona_sandbox_tool/daytona_file_tool.py","lineNumber":203,"sourceCode":"    @model_validator(mode=\"after\")\n    def _validate_action_args(self) -> DaytonaFileToolSchema:\n        if self.action != \"replace\" and not self.path:\n            raise ValueError(f\"action={self.action!r} requires 'path'.\")\n        if self.action == \"append\" and self.content is None:\n            raise ValueError(\n                \"action='append' requires 'content'. Pass the chunk to append \"\n                \"in the 'content' field.\"\n            )\n        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:","sourceCodeStart":185,"sourceCodeEnd":221,"githubUrl":"https://github.com/crewAIInc/crewAI/blob/754d7323beb2fd042e33444a115ea2d5a47193f0/lib/crewai-tools/src/crewai_tools/tools/daytona_sandbox_tool/daytona_file_tool.py#L185-L221","documentation":"DaytonaFileToolSchema._validate_action_args enforces that action='chmod' changes something: at least one of mode (permissions string like '0755'), owner, or group must be provided. With none set the validator raises ValueError, since a chmod that alters nothing is almost certainly a caller mistake.","triggerScenarios":"Calling DaytonaFileTool with action='chmod' and only a path (no mode/owner/group); passing the permission into a misnamed field; intending 'mkdir with mode' (a different action) instead of chmod.","commonSituations":"Agent omits the permission argument; caller uses 'permissions' or 'perm' as the field name instead of 'mode'; confusion between action='mkdir' (accepts mode) and action='chmod'.","solutions":["Provide at least one change target: tool.run(action='chmod', path='/workspace/script.sh', mode='0755').","To change ownership instead: pass owner='user' and/or group='group'.","Verify field names: it is 'mode', 'owner', 'group' — not 'permissions'."],"exampleFix":"# before\ntool.run(action=\"chmod\", path=\"/workspace/script.sh\")  # ValueError\n\n# after\ntool.run(action=\"chmod\", path=\"/workspace/script.sh\", mode=\"0755\")","handlingStrategy":"validation","validationCode":"def validate_chmod(path: str | None, mode: str | None, owner: str | None, group: str | None) -> None:\n    if not path:\n        raise ValueError(\"chmod requires path\")\n    if not (mode or owner or group):\n        raise ValueError(\"chmod requires mode and/or owner and/or group\")\n\nvalidate_chmod(path, mode, owner, group)","typeGuard":null,"tryCatchPattern":"try:\n    tool.run(action=\"chmod\", path=p, mode=m)\nexcept ValidationError as e:\n    if \"'mode', 'owner', or 'group'\" in str(e):\n        tool.run(action=\"chmod\", path=p, mode=\"0644\")\n    else:\n        raise","preventionTips":["Default the mode yourself (e.g. '0644') when callers do not choose one.","Use the exact field names mode/owner/group.","Do not confuse chmod with mkdir-with-mode."],"tags":["daytona","pydantic","validation","input-validation","permissions"],"backgroundTag":null,"analyzedSha":"754d7323beb2fd042e33444a115ea2d5a47193f0","analyzedAt":"2026-08-15T04:06:56.746Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}