{"record":{"id":"795b9b303fe6a97c","repo":"crewAIInc/crewAI","slug":"action-self-action-r-requires-path","errorCode":null,"errorMessage":"action={self.action!r} requires 'path'.","messagePattern":"action=(.+?) requires 'path'\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"lib/crewai-tools/src/crewai_tools/tools/daytona_sandbox_tool/daytona_file_tool.py","lineNumber":188,"sourceCode":"        default=None,\n        description=(\n            \"For action='replace': list of absolute file paths in which to \"\n            \"replace 'pattern' with 'replacement'.\"\n        ),\n    )\n    owner: str | None = Field(\n        default=None,\n        description=\"For action='chmod': new file owner (user name).\",\n    )\n    group: str | None = Field(\n        default=None,\n        description=\"For action='chmod': new file group.\",\n    )\n\n    @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\":","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/crewAIInc/crewAI/blob/754d7323beb2fd042e33444a115ea2d5a47193f0/lib/crewai-tools/src/crewai_tools/tools/daytona_sandbox_tool/daytona_file_tool.py#L170-L206","documentation":"DaytonaFileToolSchema's Pydantic model_validator(_validate_action_args) enforces per-action required arguments. Every action except 'replace' operates on a single 'path', so when action is anything other than 'replace' and path is missing/falsy, validation fails with this ValueError (surfaced as pydantic.ValidationError). It fires at input-schema construction time, before any sandbox is created.","triggerScenarios":"Invoking DaytonaFileTool with action='read'/'write'/'append'/'list'/'delete'/'mkdir'/'move'/'find'/'search'/'chmod' but no path argument; an LLM emitting a tool call with only action set; path passed as empty string.","commonSituations":"Agent omits path in tool arguments; caller confuses 'replace' (multi-file, uses paths) with single-file actions and passes paths=[] only; empty-string path from template interpolation.","solutions":["Include a non-empty path for the chosen action, e.g. tool.run(action='read', path='/workspace/main.py').","For bulk find-and-replace across many files, use action='replace' with paths=[...], pattern=..., replacement=... instead of omitting path.","If an LLM drives the tool, make the schema descriptions explicit that path is required for all non-replace actions (the field descriptions already state this).","Log the raw tool arguments before the call to spot omitted fields."],"exampleFix":"# before\ntool.run(action=\"read\")  # missing path\n\n# after\ntool.run(action=\"read\", path=\"/workspace/main.py\")","handlingStrategy":"validation","validationCode":"def validate_file_tool_args(action: str, path: str | None) -> None:\n    if action != \"replace\" and not path:\n        raise ValueError(f\"action={action!r} requires 'path'\")\n\nvalidate_file_tool_args(action, path)  # before tool.run(...)","typeGuard":null,"tryCatchPattern":"from pydantic import ValidationError\n\ntry:\n    result = tool.run(action=action, path=path)\nexcept ValidationError as e:\n    if \"requires 'path'\" in str(e):\n        # ask caller/LLM for the missing path and retry\n        path = request_path()\n        result = tool.run(action=action, path=path)\n    else:\n        raise","preventionTips":["Build tool arguments via the DaytonaFileToolSchema model so validation errors surface at your boundary.","For agents, include example calls with path in the tool prompt.","Centralize a pre-call argument checker per action."],"tags":["daytona","pydantic","validation","input-validation","filesystem"],"backgroundTag":null,"analyzedSha":"754d7323beb2fd042e33444a115ea2d5a47193f0","analyzedAt":"2026-08-15T04:06:56.746Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}