{"record":{"id":"26c8f995f25abe54","repo":"crewAIInc/crewAI","slug":"action-exists-requires-path","errorCode":null,"errorMessage":"action='exists' requires 'path'","messagePattern":"action='exists' 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":288,"sourceCode":"                return self._list(sandbox, path)\n            if action == \"delete\":\n                if path is None:\n                    raise ValueError(\"action='delete' requires 'path'\")\n                sandbox.fs.delete_file(path, recursive=recursive)\n                return {\"status\": \"deleted\", \"path\": path}\n            if action == \"mkdir\":\n                if path is None:\n                    raise ValueError(\"action='mkdir' requires 'path'\")\n                mkdir_mode = mode or \"0755\"\n                sandbox.fs.create_folder(path, mkdir_mode)\n                return {\"status\": \"created\", \"path\": path, \"mode\": mkdir_mode}\n            if action == \"info\":\n                if path is None:\n                    raise ValueError(\"action='info' requires 'path'\")\n                return self._info(sandbox, path)\n            if action == \"exists\":\n                if path is None:\n                    raise ValueError(\"action='exists' requires 'path'\")\n                return self._exists(sandbox, path)\n            if action == \"move\":\n                if path is None or destination is None:\n                    raise ValueError(\"action='move' requires 'path' and 'destination'\")\n                sandbox.fs.move_files(path, destination)\n                return {\"status\": \"moved\", \"from\": path, \"to\": destination}\n            if action == \"find\":\n                if path is None or pattern is None:\n                    raise ValueError(\"action='find' requires 'path' and 'pattern'\")\n                return self._find(sandbox, path, pattern)\n            if action == \"search\":\n                if path is None or pattern is None:\n                    raise ValueError(\"action='search' requires 'path' and 'pattern'\")\n                return self._search(sandbox, path, pattern)\n            if action == \"chmod\":\n                if path is None:\n                    raise ValueError(\"action='chmod' requires 'path'\")\n                return self._chmod(sandbox, path, mode=mode, owner=owner, group=group)","sourceCodeStart":270,"sourceCodeEnd":306,"githubUrl":"https://github.com/crewAIInc/crewAI/blob/754d7323beb2fd042e33444a115ea2d5a47193f0/lib/crewai-tools/src/crewai_tools/tools/daytona_sandbox_tool/daytona_file_tool.py#L270-L306","documentation":"For action='exists' DaytonaFileTool._run needs a 'path' to test existence via self._exists(sandbox, path). With path=None it raises ValueError immediately; the sandbox is never contacted. This check runs before any I/O, so catching it early costs nothing.","triggerScenarios":"Calling _run(action='exists') without path; an agent probing 'does the file exist?' but forgetting to include the filename; passing the path inside a nested dict instead of as the top-level 'path' kwarg.","commonSituations":"Agents that phrase existence checks in natural language and the tool-call formatter drops the path; testing the tool with a bare action string.","solutions":["Pass the target explicitly: _run(action='exists', path='/workspace/in.txt').","Add a pre-call guard in your orchestrator that rejects action='exists' without a path.","Fix the agent prompt/tool description so existence checks always carry the full path."],"exampleFix":"# before\nfile_tool._run(action='exists')\n\n# after\nfile_tool._run(action='exists', path='/workspace/inputs/data.csv')","handlingStrategy":"validation","validationCode":"def file_exists(file_tool, path: str) -> bool:\n    if not path or not isinstance(path, str):\n        raise ValueError(\"path must be a non-empty string for action='exists'\")\n    return bool(file_tool._run(action='exists', path=path).get('exists'))","typeGuard":"def is_nonempty_path(value: object) -> bool:\n    return isinstance(value, str) and bool(value.strip())","tryCatchPattern":"try:\n    result = file_tool._run(action='exists', path=path)\nexcept ValueError as e:\n    if \"requires 'path'\" in str(e):\n        return False  # cannot probe without a target; treat as unknown\n    raise","preventionTips":["Type-annotate wrappers so None cannot reach the tool.","Validate agent-emitted JSON against a schema before dispatch.","Default missing paths to a known workspace root instead of None."],"tags":["daytona","argument-validation","file-tool","exists"],"backgroundTag":null,"analyzedSha":"754d7323beb2fd042e33444a115ea2d5a47193f0","analyzedAt":"2026-08-15T04:06:56.746Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}