zylon-ai/private-gpt · error · ValueError

Path '{path}' is in a read-only mount ('{prefix}').

Error message

Path '{path}' is in a read-only mount ('{prefix}').

What it means

The local sandbox registers mounts as writable or read-only; _assert_writable walks the read-only prefix list and raises ValueError if a target path starts with any read-only mount prefix. It protects host-backed storage that was mounted with read-only semantics from being mutated by sandbox operations (file writes, renames, deletions).

Source

Thrown at private_gpt/components/sandbox/local.py:76

    ) -> None:
        """Register a new host-path mount after session creation."""
        self._translator.register(canonical, host_path, writable)
        if not writable and canonical not in self._readonly:
            self._readonly.append(canonical)

    def remove_local_mount(self, canonical: str) -> None:
        """Unregister a mount — does not delete files from host storage."""
        self._translator.unregister(canonical)
        self._readonly = [p for p in self._readonly if p != canonical]

    async def remove_mount(self, canonical_path: str) -> None:
        """Unregister a local mount without touching host-backed storage files."""
        self.remove_local_mount(canonical_path)

    def _assert_writable(self, path: str) -> None:
        for prefix in self._readonly:
            if path.startswith(prefix):
                raise ValueError(f"Path '{path}' is in a read-only mount ('{prefix}').")

    async def exec(
        self, command: str, opts: SandboxExecOptions | None = None
    ) -> SandboxExecutionResult:
        cwd = self._translator.to_real(
            (opts.cwd if opts else None) or self._default_cwd
        )
        cmd = self._translator.rewrite_command(command)
        result = await self._executor.run(
            cmd, cwd=cwd, timeout=opts.timeout if opts else None
        )
        return SandboxExecutionResult(
            success=result.success,
            stdout=self._translator.scrub_output(result.stdout),
            stderr=self._translator.scrub_output(result.stderr),
            exit_code=result.exit_code,
            execution_time_ms=result.execution_time_ms,
        )

View on GitHub (pinned to 4a030776a3)

Solutions

  1. Write to a writable location (scratch/workdir mount) instead of the read-only prefix.
  2. If mutation is genuinely required, re-register the mount without the read-only flag (a deployment decision — read-only is usually deliberate for source data).
  3. Check the exact prefix strings: the check is path.startswith(prefix), so trailing slashes and case differences matter; normalize paths before comparing.
  4. Copy the file out of the read-only mount, modify the copy, then use it.

Example fix

# before
await sandbox.write_file("/mnt/corpus/report.txt", data)  # ValueError: read-only mount

# after
await sandbox.write_file("/mnt/scratch/report.txt", data)
Defensive patterns

Strategy: validation

Validate before calling

def ensure_writable(sandbox, path: str) -> bool:
    try:
        sandbox._assert_writable(path)
        return True
    except ValueError:
        return False

# or track mount flags yourself
WRITABLE_ROOTS = ["/mnt/scratch"]
def writable_path(p: str) -> str:
    return p if any(p.startswith(r, 0) for r in WRITABLE_ROOTS) else "/mnt/scratch/out"

Try / catch

try:
    await sandbox.write_file(path, data)
except ValueError as e:
    if "read-only mount" in str(e):
        path = "/mnt/scratch/" + Path(path).name
        await sandbox.write_file(path, data)
    else:
        raise

Prevention

When it happens

Trigger: Any sandbox operation that calls _assert_writable(path) where path falls under a canonical prefix registered via add_local_mount(..., readonly=True) (or default read-only mounts) — e.g. writing generated files into a mounted knowledge/corpus directory.

Common situations: Agents/tools attempting to write outputs into a mounted source-data directory; mismatch between the canonical path used to register the mount and the path used at write time (prefix string comparison); forgetting that skills/corpus mounts are read-only by design.

Related errors


AI-assisted analysis of zylon-ai/private-gpt@4a030776a3 (2026-08-15). Data as JSON: /api/errors/daea5b1c5ae1dc8f. Report an issue: GitHub.