Tencent/WeKnora · error

sandbox: workspace write path %q is outside %s

Error message

sandbox: workspace write path %q is outside %s

What it means

WriteSessionWorkspaceFile sanitizes the requested path through cleanSessionWorkspaceWritePath before writing. This error is returned when the cleaned path is absolute and a real file path but does not live under the session workspace root /workspace (e.g. /etc/passwd, /tmp/x, /workspace-evil/file). The sandbox deliberately restricts writes to /workspace to keep agent output contained.

Source

Thrown at internal/sandbox/session_manager.go:1028

	return "", fmt.Errorf(
		"sandbox: session input path %q is outside %s",
		filePath, SessionInputRoot,
	)
}

// cleanSessionWorkspaceWritePath keeps model-authored writes inside the
// session workspace and out of the attachment tree. Validation is lexical
// (path.Clean plus prefix checks), matching cleanSessionWorkDir.
func cleanSessionWorkspaceWritePath(filePath string) (string, error) {
	clean := path.Clean(strings.TrimSpace(filePath))
	if !path.IsAbs(clean) || clean == "." || clean == "/" {
		return "", fmt.Errorf("sandbox: workspace write path %q must be an absolute file path", filePath)
	}
	if clean == SessionWorkspaceRoot || clean == SessionOutputRoot || clean == SessionInputRoot {
		return "", fmt.Errorf("sandbox: workspace write path %q is a directory, not a file", filePath)
	}
	if !strings.HasPrefix(clean, SessionWorkspaceRoot+"/") {
		return "", fmt.Errorf("sandbox: workspace write path %q is outside %s", filePath, SessionWorkspaceRoot)
	}
	if strings.HasPrefix(clean, SessionInputRoot+"/") {
		return "", fmt.Errorf("sandbox: session input %s is read-only", SessionInputRoot)
	}
	return clean, nil
}

// cleanSessionWorkDir keeps shell_exec inside directories we are willing to let
// an agent work in. Ordinary sessions get /workspace only.
//
// Validation is lexical (path.Clean plus prefix checks): a symlink under an
// allowed root that resolves elsewhere at execution time is not detected and
// that is intentional. The only caller that passes allowSkillsRoot also passes
// AsRoot and runs arbitrary install shell commands, so a symlink would grant
// nothing those commands cannot already reach via cd or absolute paths. For
// ordinary sessions the allowlist is unchanged and its lexical nature is
// pre-existing. The allowlist stops casual wandering and makes intent
// auditable; the real isolation boundary is the remote sandbox itself.

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Rewrite the path to be under /workspace, e.g. "/workspace/output/report.txt".
  2. Call filepath.Clean/Join yourself before calling and verify strings.HasPrefix(cleaned, "/workspace/") to fail fast with a clearer message.
  3. If the data is an input attachment, read it via the input-path API instead of attempting a write into /workspace/input.

Example fix

// before
err := mgr.WriteSessionWorkspaceFile(ctx, session, "/tmp/report.txt", data)
// after
err := mgr.WriteSessionWorkspaceFile(ctx, session, "/workspace/output/report.txt", data)
Defensive patterns

Strategy: validation

Validate before calling

func isWorkspaceWritePath(p string) bool {
    c := filepath.Clean(p)
    return filepath.IsAbs(c) && strings.HasPrefix(c, "/workspace/") &&
        c != "/workspace/input" && !strings.HasPrefix(c, "/workspace/input/")
}
if !isWorkspaceWritePath(p) { /* fix path before calling */ }

Type guard

func safeWorkspacePath(p string) (string, bool) {
    c := filepath.Clean(p)
    if !filepath.IsAbs(c) || !strings.HasPrefix(c, "/workspace/") {
        return "", false
    }
    return c, true
}

Try / catch

out, err := mgr.WriteSessionWorkspaceFile(ctx, s, path, data)
if err != nil {
    return fmt.Errorf("write workspace file %q: %w", path, err)
}

Prevention

When it happens

Trigger: Calling WriteSessionWorkspaceFile (or the test helper path) with a file path whose cleaned value is not prefixed by "/workspace/" — e.g. absolute paths to other directories, or paths that clean to something outside /workspace such as "/workspace/../etc/hosts".

Common situations: Hardcoding an OS temp path or a host-relative path instead of a /workspace-relative one; constructing paths with ".." segments that escape the workspace; migrating code that previously wrote to arbitrary directories.

Related errors


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/96389447b511ad6f. Report an issue: GitHub.