{"record":{"id":"185a34e2e1f2bf2c","repo":"crewAIInc/crewAI","slug":"action-read-requires-path","errorCode":null,"errorMessage":"action='read' requires 'path'","messagePattern":"action='read' 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":257,"sourceCode":"        self,\n        action: FileAction,\n        path: str | None = None,\n        content: str | None = None,\n        binary: bool = False,\n        recursive: bool = False,\n        mode: str | None = None,\n        destination: str | None = None,\n        pattern: str | None = None,\n        replacement: str | None = None,\n        paths: list[str] | None = None,\n        owner: str | None = None,\n        group: str | None = None,\n    ) -> Any:\n        sandbox, should_delete = self._acquire_sandbox()\n        try:\n            if action == \"read\":\n                if path is None:\n                    raise ValueError(\"action='read' requires 'path'\")\n                return self._read(sandbox, path, binary=binary)\n            if action == \"write\":\n                if path is None:\n                    raise ValueError(\"action='write' requires 'path'\")\n                return self._write(sandbox, path, content or \"\", binary=binary)\n            if action == \"append\":\n                if path is None:\n                    raise ValueError(\"action='append' requires 'path'\")\n                return self._append(sandbox, path, content or \"\", binary=binary)\n            if action == \"list\":\n                if path is None:\n                    raise ValueError(\"action='list' requires 'path'\")\n                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}","sourceCodeStart":239,"sourceCodeEnd":275,"githubUrl":"https://github.com/crewAIInc/crewAI/blob/754d7323beb2fd042e33444a115ea2d5a47193f0/lib/crewai-tools/src/crewai_tools/tools/daytona_sandbox_tool/daytona_file_tool.py#L239-L275","documentation":"Inside DaytonaFileTool._run, each action re-checks its required argument defensively. For action='read' a None path raises ValueError(\"action='read' requires 'path'\"). Under normal use the Pydantic schema validator already rejects a missing path, so this branch is only reachable when _run is invoked directly (bypassing schema validation), e.g. in tests or custom wiring.","triggerScenarios":"Calling tool._run(action='read', path=None, ...) directly instead of tool.run(...) / validated invocation; subclass or test harness that constructs arguments programmatically and skips the Pydantic model_validator.","commonSituations":"Unit tests exercising _run directly; custom tool wrappers calling the private method; monkeypatched paths where the schema step is skipped.","solutions":["Invoke the tool through its public API (tool.run / BaseToolInputModel-validated path) so the schema catches bad input first.","If calling _run directly, always pass a concrete path: tool._run(action='read', path='/workspace/file.txt').","In tests, build arguments via the schema: DaytonaFileToolSchema(action='read', path=...).model_dump()."],"exampleFix":"# before\ntool._run(action=\"read\", path=None)  # ValueError\n\n# after\ntool.run(action=\"read\", path=\"/workspace/main.py\")","handlingStrategy":"validation","validationCode":"def validated_read_call(tool, path: str | None) -> Any:\n    if path is None:\n        raise ValueError(\"action='read' requires an explicit path\")\n    return tool.run(action=\"read\", path=path)  # schema-validated invocation","typeGuard":null,"tryCatchPattern":"try:\n    data = tool.run(action=\"read\", path=p)\nexcept ValueError as e:\n    if \"requires 'path'\" in str(e):\n        p = resolve_default_file()\n        data = tool.run(action=\"read\", path=p)\n    else:\n        raise","preventionTips":["Never call _run directly; use run() so Pydantic validation runs first.","Default missing paths at your call site instead of passing None.","Cover the read action in integration tests with both valid and missing paths."],"tags":["daytona","filesystem","validation","internal-api"],"backgroundTag":null,"analyzedSha":"754d7323beb2fd042e33444a115ea2d5a47193f0","analyzedAt":"2026-08-15T04:06:56.746Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}