crewAIInc/crewAI · error · ValueError

action='move' requires 'destination'.

Error message

action='move' requires 'destination'.

What it means

DaytonaFileToolSchema._validate_action_args enforces that action='move' includes a non-empty destination (the target path to move/rename to). Without it the validator raises ValueError before any sandbox operation starts.

Source

Thrown at lib/crewai-tools/src/crewai_tools/tools/daytona_sandbox_tool/daytona_file_tool.py:195

        default=None,
        description="For action='chmod': new file owner (user name).",
    )
    group: str | None = Field(
        default=None,
        description="For action='chmod': new file group.",
    )

    @model_validator(mode="after")
    def _validate_action_args(self) -> DaytonaFileToolSchema:
        if self.action != "replace" and not self.path:
            raise ValueError(f"action={self.action!r} requires 'path'.")
        if self.action == "append" and self.content is None:
            raise ValueError(
                "action='append' requires 'content'. Pass the chunk to append "
                "in the 'content' field."
            )
        if self.action == "move" and not self.destination:
            raise ValueError("action='move' requires 'destination'.")
        if self.action == "find" and not self.pattern:
            raise ValueError(
                "action='find' requires 'pattern' (text to search for inside files)."
            )
        if self.action == "search" and not self.pattern:
            raise ValueError("action='search' requires 'pattern' (glob, e.g. '*.py').")
        if self.action == "chmod" and not (self.mode or self.owner or self.group):
            raise ValueError(
                "action='chmod' requires at least one of 'mode', 'owner', or 'group'."
            )
        if self.action == "replace":
            if not self.paths:
                raise ValueError(
                    "action='replace' requires 'paths' (list of file paths)."
                )
            if not self.pattern:
                raise ValueError("action='replace' requires 'pattern'.")
            if self.replacement is None:

View on GitHub (pinned to 754d7323be)

Solutions

  1. Supply destination: tool.run(action='move', path='/workspace/old.txt', destination='/workspace/new.txt').
  2. If a destination variable is computed upstream, assert it is non-empty before the tool call.
  3. Update the agent prompt/tool description so 'move' always produces both source and target paths.

Example fix

# before
tool.run(action="move", path="/workspace/old.txt")  # ValueError

# after
tool.run(action="move", path="/workspace/old.txt", destination="/workspace/new.txt")
Defensive patterns

Strategy: validation

Validate before calling

def validate_move(path: str | None, destination: str | None) -> None:
    if not path or not destination:
        raise ValueError("move requires both source 'path' and 'destination'")

validate_move(path, destination)

Try / catch

try:
    tool.run(action="move", path=p, destination=d)
except ValidationError as e:
    if "requires 'destination'" in str(e):
        d = derive_destination(p)
        tool.run(action="move", path=p, destination=d)
    else:
        raise

Prevention

When it happens

Trigger: Calling DaytonaFileTool with action='move' and path set but destination omitted or empty; an agent tool call that includes the source but forgets the target.

Common situations: LLM emits partial move arguments; caller assumes rename-in-place without destination; destination variable evaluates to '' because the target path was never computed.

Related errors


AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15). Data as JSON: /api/errors/98f8ffc224b21a50. Report an issue: GitHub.