openclaw/openclaw · critical · Error
foreign file owner
Error message
foreign file owner
What it means
On non-Windows platforms, validateOwnedFile requires the manifest and launcher files to be owned by the current process uid (process.getuid()). A file whose lstat uid differs from the process uid throws. This prevents the native host from trusting files controlled by another user.
Source
Thrown at extensions/browser/src/browser/extension-native-host.ts:74
}
}
validateExpectedOrigins(expectedOrigins);
if (!EXTENSION_ORIGIN_PATTERN.test(callerOrigin)) {
throw new Error("missing Chrome extension origin");
}
return { expectedOrigins, callerOrigin };
}
async function validateOwnedFile(filePath: string, executable: boolean): Promise<string> {
const resolved = path.resolve(filePath);
const info = await fs.lstat(resolved);
if (!info.isFile() || info.isSymbolicLink()) {
throw new Error("unsafe file type");
}
if (process.platform !== "win32") {
const uid = process.getuid?.();
if (uid !== undefined && info.uid !== uid) {
throw new Error("foreign file owner");
}
const mode = info.mode & 0o777;
if ((mode & 0o077) !== 0 || (executable && (mode & 0o100) === 0)) {
throw new Error("unsafe file mode");
}
}
const canonical = await fs.realpath(resolved);
if (canonical !== resolved) {
throw new Error("non-canonical file path");
}
return canonical;
}
async function validateNativeManifest(params: {
manifestPath: string;
launcherPath: string;
callerOrigin: string;
expectedOrigins: string[];View on GitHub (pinned to 01804a7531)
Solutions
- Reinstall as the same user account that runs the browser and native host.
- chown the manifest and launcher files to the current user if that is intentional and safe.
- Run `openclaw doctor --fix` under the correct user account to repair ownership.
Example fix
// before: files owned by root after a sudo install
// sudo chown -R $USER "$OPENCLAW_STATE_DIR/browser"
// after: reinstall as the normal user
await installChromeExtensionBootstrap({ bundledDir, pluginRoot, deps }); Defensive patterns
Strategy: try-catch
Validate before calling
import fs from "node:fs/promises";
async function fileOwnedByCurrentUser(p: string): Promise<boolean> {
if (process.platform === "win32") return true;
const uid = process.getuid?.();
if (uid === undefined) return true;
try {
const st = await fs.lstat(p);
return st.uid === uid;
} catch {
return false;
}
} Try / catch
try {
await validateNativeManifest(params);
} catch (error) {
if (error instanceof Error && error.message === "foreign file owner") {
// chown the file to the current user or reinstall under the correct account
}
} Prevention
- Install and run the native host under the same user account.
- Avoid `sudo` for installs that create per-user native messaging files.
- Run `openclaw doctor --fix` as the browser user after ownership changes.
When it happens
Trigger: validateOwnedFile runs under process.getuid() === A but the manifest or launcher file's stat uid is B (different user).
Common situations: The extension was installed under a different user account; running the native host after a `sudo install` changed ownership to root; a multi-user machine where another user's OpenClaw owns the files; OPENCLAW_STATE_DIR points at a shared location owned by another user.
Related errors
- unsafe file mode
- Refusing to overwrite ${existing.state} native host: ${manif
- Refusing to overwrite foreign native host launcher: ${launch
- unsafe file type
- non-canonical file path
AI-assisted analysis of openclaw/openclaw@01804a7531 (2026-08-12).
Data as JSON: /api/errors/6b0cd9e2c4cc9e35.
Report an issue: GitHub.