From 73c1543d8fdb82b8943509b8a4768c0da8874d66 Mon Sep 17 00:00:00 2001 From: Kagura Chen Date: Mon, 23 Mar 2026 12:44:47 +0800 Subject: [PATCH 1/3] fix(install): ensure .openclaw-data ownership for sandbox user (fixes #692) The native curl installer may create .openclaw-data directories as root, causing EACCES when openclaw (running as the sandbox user) tries to write device-auth.json to the identity directory. Add a startup ownership check to nemoclaw-start.sh that: - Creates any missing writable subdirectories (mirrors Dockerfile setup) - Fixes ownership if files are not owned by the current user - Creates the identity symlink if missing on native installs The Docker path is unaffected (Dockerfile already sets correct ownership). --- scripts/nemoclaw-start.sh | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/scripts/nemoclaw-start.sh b/scripts/nemoclaw-start.sh index d28b96374..bbed04c17 100755 --- a/scripts/nemoclaw-start.sh +++ b/scripts/nemoclaw-start.sh @@ -130,6 +130,38 @@ echo 'Setting up NemoClaw...' # openclaw doctor --fix and openclaw plugins install already ran at build time # (Dockerfile Step 28). At runtime they fail with EPERM against the locked # /sandbox/.openclaw directory and accomplish nothing. + +# Ensure writable state directories exist and are owned by the current user. +# The Docker build (Dockerfile) sets this up correctly, but the native curl +# installer may create these directories as root, causing EACCES when openclaw +# tries to write device-auth.json or other state files. Ref: #692 +fix_openclaw_data_ownership() { + local data_dir="${HOME}/.openclaw-data" + local openclaw_dir="${HOME}/.openclaw" + + # Only act when the split layout (.openclaw-data + symlinks) is present. + [ -d "$data_dir" ] || return 0 + + # Create any missing writable subdirectories (mirrors Dockerfile setup). + local subdirs="agents/main/agent extensions workspace skills hooks identity devices canvas cron" + for sub in $subdirs; do + mkdir -p "${data_dir}/${sub}" 2>/dev/null || true + done + + # Fix ownership if any files are not owned by us. + if find "$data_dir" -maxdepth 0 ! -user "$(id -u)" -print -quit 2>/dev/null | grep -q .; then + chown -R "$(id -u):$(id -g)" "$data_dir" 2>/dev/null || true + echo "[setup] fixed ownership on ${data_dir}" + fi + + # Ensure the identity symlink exists (may be missing on native installs). + if [ ! -e "${openclaw_dir}/identity" ] && [ -d "${data_dir}/identity" ]; then + ln -sf "${data_dir}/identity" "${openclaw_dir}/identity" 2>/dev/null || true + echo "[setup] created identity symlink" + fi +} +fix_openclaw_data_ownership + write_auth_profile if [ ${#NEMOCLAW_CMD[@]} -gt 0 ]; then From e8e587abfaeed3daaa4895c31f921f5a199b2304 Mon Sep 17 00:00:00 2001 From: Kagura Chen Date: Mon, 23 Mar 2026 12:56:27 +0800 Subject: [PATCH 2/3] fix: clarify ownership check comment per review feedback --- scripts/nemoclaw-start.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/nemoclaw-start.sh b/scripts/nemoclaw-start.sh index bbed04c17..7a2613a6d 100755 --- a/scripts/nemoclaw-start.sh +++ b/scripts/nemoclaw-start.sh @@ -148,7 +148,8 @@ fix_openclaw_data_ownership() { mkdir -p "${data_dir}/${sub}" 2>/dev/null || true done - # Fix ownership if any files are not owned by us. + # Fix ownership if the top-level data dir is not owned by us (common when + # the entire tree was created as root during installation). if find "$data_dir" -maxdepth 0 ! -user "$(id -u)" -print -quit 2>/dev/null | grep -q .; then chown -R "$(id -u):$(id -g)" "$data_dir" 2>/dev/null || true echo "[setup] fixed ownership on ${data_dir}" From dbc54f6d9844dda59f521168aefac73096b6f34c Mon Sep 17 00:00:00 2001 From: Kagura Chen Date: Mon, 23 Mar 2026 14:43:28 +0800 Subject: [PATCH 3/3] fix: handle broken symlinks and mixed ownership edge cases Co-Authored-By: Claude Opus 4.6 --- scripts/nemoclaw-start.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/scripts/nemoclaw-start.sh b/scripts/nemoclaw-start.sh index 7a2613a6d..cc924d304 100755 --- a/scripts/nemoclaw-start.sh +++ b/scripts/nemoclaw-start.sh @@ -150,15 +150,20 @@ fix_openclaw_data_ownership() { # Fix ownership if the top-level data dir is not owned by us (common when # the entire tree was created as root during installation). - if find "$data_dir" -maxdepth 0 ! -user "$(id -u)" -print -quit 2>/dev/null | grep -q .; then + if find "$data_dir" -maxdepth 2 ! -user "$(id -u)" -print -quit 2>/dev/null | grep -q .; then chown -R "$(id -u):$(id -g)" "$data_dir" 2>/dev/null || true echo "[setup] fixed ownership on ${data_dir}" fi # Ensure the identity symlink exists (may be missing on native installs). - if [ ! -e "${openclaw_dir}/identity" ] && [ -d "${data_dir}/identity" ]; then + # Remove any broken symlinks first to prevent conflicts. + if [ ! -L "${openclaw_dir}/identity" ] && [ ! -e "${openclaw_dir}/identity" ] && [ -d "${data_dir}/identity" ]; then ln -sf "${data_dir}/identity" "${openclaw_dir}/identity" 2>/dev/null || true echo "[setup] created identity symlink" + elif [ -L "${openclaw_dir}/identity" ] && [ ! -e "${openclaw_dir}/identity" ]; then + rm -f "${openclaw_dir}/identity" + ln -sf "${data_dir}/identity" "${openclaw_dir}/identity" 2>/dev/null || true + echo "[setup] replaced broken identity symlink" fi } fix_openclaw_data_ownership