{"record":{"id":"8c1f87da777db964","repo":"usestrix/strix","slug":"spec-has-an-empty-destination-path","errorCode":null,"errorMessage":"'{spec}' has an empty destination path","messagePattern":"'(.+?)' has an empty destination path","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"strix/interface/utils.py","lineNumber":1705,"sourceCode":"# ``--workspace-file`` places a single host file into the sandbox workspace,\n# outside every target tree. Content rides the same upload as the target\n# sources, so a large file makes session bring-up slower.\n\n\ndef _workspace_file_dest(spec: str, source: Path) -> str:\n    \"\"\"Return the workspace-relative destination declared by ``spec``.\"\"\"\n    _, sep, dest = spec.rpartition(\":\")\n    candidate = dest.strip() if sep and dest.strip() else source.name\n    if candidate.startswith(\"/\") or Path(candidate).is_absolute():\n        if not candidate.startswith(\"/workspace/\"):\n            raise ValueError(\n                f\"'{spec}' must land inside the workspace: use a relative \"\n                \"destination or a path under /workspace\"\n            )\n        candidate = candidate.removeprefix(\"/workspace/\")\n    candidate = candidate.strip(\"/\")\n    if not candidate:\n        raise ValueError(f\"'{spec}' has an empty destination path\")\n    if any(part in (\"\", \".\", \"..\") for part in candidate.split(\"/\")):\n        raise ValueError(f\"'{spec}' has an invalid destination path: {candidate}\")\n    # A control character would let the path span more than the one line it is\n    # rendered on in the agent task, so the whole spec is rejected.\n    if any(ord(char) < 0x20 or ord(char) == 0x7F for char in candidate):\n        raise ValueError(f\"'{spec}' has a control character in its destination path\")\n    return candidate\n\n\ndef resolve_workspace_files(specs: list[str] | None) -> list[dict[str, str]]:\n    \"\"\"Validate ``PATH[:DEST]`` specs into source/destination pairs.\n\n    Each spec names a readable host file. ``DEST`` is the path inside\n    ``/workspace``; it defaults to the file name. Raises ``ValueError`` with a\n    user-facing message when a spec is unusable.\n    \"\"\"\n    resolved: list[dict[str, str]] = []\n    seen: dict[str, str] = {}","sourceCodeStart":1687,"sourceCodeEnd":1723,"githubUrl":"https://github.com/usestrix/strix/blob/85513391305171ecc6faffe03da4a8bda5e3febb/strix/interface/utils.py#L1687-L1723","documentation":"Raised by _workspace_file_dest() when the destination component of a --workspace-file spec resolves to an empty string after stripping slashes and the /workspace/ prefix. This means the spec explicitly declared a destination but it contains nothing usable, e.g. 'file.txt:' or ':'.","triggerScenarios":"Passing a spec ending in a bare colon or slashes: --workspace-file notes.txt: or --workspace-file a.txt:/workspace///. After rpartition(':') the dest part is non-empty whitespace or only slashes, which strip to empty and trigger the ValueError.","commonSituations":"Shell quoting mistake leaves a trailing ':' (e.g. building specs with \"${FILE}:${DEST}\" where DEST is an unset/empty variable), or a user mimics a PATH:DEST syntax with an intentionally empty DEST thinking it means 'default'.","solutions":["Remove the trailing colon so the destination defaults to the file name: --workspace-file notes.txt","If DEST comes from a variable, ensure it is non-empty: --workspace-file \"a.txt:${DEST:-a.txt}\"","Put an actual relative path after the colon: --workspace-file a.txt:configs/a.txt"],"exampleFix":"# before (DEST empty at runtime)\nstrix --workspace-file \"a.txt:$DEST\" -t ./\n# after\nstrix --workspace-file \"a.txt:${DEST:-a.txt}\" -t ./","handlingStrategy":"validation","validationCode":"def normalize_spec(spec: str) -> str:\n    raw, sep, dest = spec.rpartition(\":\")\n    if sep and not dest.strip():\n        return raw  # drop empty ':DEST' tail, default to source name\n    return spec","typeGuard":null,"tryCatchPattern":"try:\n    resolve_workspace_files(specs)\nexcept ValueError as e:\n    exit(f\"bad --workspace-file spec: {e}\")","preventionTips":["When building specs from variables, provide a default: f\"{src}:{dest or Path(src).name}\"","Lint specs in CI: reject any ending in ':' with blank DEST","Prefer omitting :DEST when the default basename suffices"],"tags":["strix","cli","validation","workspace-files"],"backgroundTag":null,"analyzedSha":"85513391305171ecc6faffe03da4a8bda5e3febb","analyzedAt":"2026-08-15T05:03:57.275Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}