openclaw - ✅(Solved) Fix [Bug]: exec-approvals.json file is stored in ~/.openclaw despite OPENCLAW_STATE_DIR is set to ~/openclaw [3 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#75204Fetched 2026-05-01 05:36:54
View on GitHub
Comments
1
Participants
2
Timeline
12
Reactions
2
Timeline (top)
subscribed ×5cross-referenced ×3mentioned ×2commented ×1

In as installation with OPENCLAW_STATE_DIR set to ~/openclaw, the file exec-approvals.json is still stored in ~/.openclaw

Root Cause

When openclaw doctor is launched, this problem is returned

◇  State integrity ──────────────────────────────────────────────────────────────╮
│                                                                                │
│  - OAuth dir not present (~/openclaw/credentials). Skipping create because no  │
│    WhatsApp/pairing channel config is active.                                  │
│  - Multiple state directories detected. This can split session history.        │
│    - ~/.openclaw                                                               │
│    Active state dir: ~/openclaw                                                │
│                                                                                │
├────────────────────────────────────────────────────────────────────────────────╯

Fix Action

Fixed

PR fix notes

PR #75210: fix(infra): honor OPENCLAW_STATE_DIR for exec-approvals.json (#75204)

Description (problem / solution / changelog)

Summary

  • Problem: with OPENCLAW_STATE_DIR=~/openclaw, exec-approvals.json (and its IPC socket) still landed in ~/.openclaw/. openclaw doctor then warned 'Multiple state directories detected' because two roots existed for one install. Reported in #75204.
  • Root cause: resolveExecApprovalsPath() and resolveExecApprovalsSocketPath() in src/infra/exec-approvals.ts hard-coded ~/.openclaw/... and called expandHomePrefix(), which doesn't honor OPENCLAW_STATE_DIR. Other infra paths (device-auth-store.ts, restart-sentinel.ts, push-web.ts, allow-from-store-file.ts) already route through resolveStateDir().
  • What changed: the two resolver functions now path.join(resolveStateDir(), ...) so OPENCLAW_STATE_DIR is consistently honored alongside the rest of openclaw's persistent state layout.

Linked Issue

  • Closes #75204
  • This PR fixes a bug or regression

Test Plan

  • pnpm tsgo:core — clean
  • pnpm exec oxfmt --check --threads=1 src/infra/exec-approvals.ts — clean

Changed files

  • src/infra/exec-approvals.ts (modified, +7/-4)

PR #75222: fix(exec-approvals): honor OPENCLAW_STATE_DIR for exec-approvals.json and .sock

Description (problem / solution / changelog)

Summary

exec-approvals.json and exec-approvals.sock were hardcoded to ~/.openclaw regardless of OPENCLAW_STATE_DIR, creating a split-state condition when the env var is set. Users with OPENCLAW_STATE_DIR=~/openclaw saw the active state dir used for sessions and config, but exec-approvals.json still written to ~/.openclaw — triggering openclaw doctor warnings about multiple state directories.

Root cause: DEFAULT_FILE = "~/.openclaw/exec-approvals.json" and DEFAULT_SOCKET = "~/.openclaw/exec-approvals.sock" were expanded with expandHomePrefix rather than resolveStateDir(). Other infra files (device-identity.ts, voicewake.ts, push-web.ts) already correctly use resolveStateDir().

Fix:

  • Replace hardcoded constants with path.join(resolveStateDir(), filename) in resolveExecApprovalsPath() and resolveExecApprovalsSocketPath()
  • Remove now-unused DEFAULT_FILE / DEFAULT_SOCKET constants
  • Update exec-approvals-effective.ts DEFAULT_HOST_PATH to use resolveExecApprovalsPath() instead

Test:

  • New regression test: OPENCLAW_STATE_DIR=/custom/state → both paths resolve under /custom/state
  • Updated 10 policy test expectations to derive hostSource from resolveExecApprovalsPath() rather than the literal ~/.openclaw string (so tests work on any machine/config)
  • 49/49 tests pass

Fixes #75204.

Changed files

  • src/infra/exec-approvals-effective.ts (modified, +2/-2)
  • src/infra/exec-approvals-policy.test.ts (modified, +13/-10)
  • src/infra/exec-approvals.test.ts (modified, +21/-0)
  • src/infra/exec-approvals.ts (modified, +5/-4)

PR #75292: fix(exec-approvals): honor OPENCLAW_STATE_DIR for the on-disk file and socket

Description (problem / solution / changelog)

Closes #75204.

Problem

resolveExecApprovalsPath() and resolveExecApprovalsSocketPath() in src/infra/exec-approvals.ts hardcoded ~/.openclaw/exec-approvals.json and ~/.openclaw/exec-approvals.sock and expanded them through expandHomePrefix(). That call only resolves the ~ prefix; it does not consult OPENCLAW_STATE_DIR.

Operators who set OPENCLAW_STATE_DIR=~/openclaw (or any non-default state dir) end up with two state directories on disk:

  • The configured ~/openclaw/ holding everything else (sessions, credentials, plugin state, …)
  • A stray ~/.openclaw/ containing only exec-approvals.json

openclaw doctor then warns:

Multiple state directories detected. This can split session history.
  - ~/.openclaw
  - ~/openclaw

…while the responsible writer keeps recreating the split on every approval write. The full reproduction is in the linked issue.

Fix

Route both resolver helpers through resolveStateDir(env) from src/config/paths.ts, the same utility every other persisted artifact already uses (sessions, pairing store, push-web subscriptions, state migrations, plugin runtime caches, etc.).

-const DEFAULT_SOCKET = "~/.openclaw/exec-approvals.sock";
-const DEFAULT_FILE = "~/.openclaw/exec-approvals.json";
+const EXEC_APPROVALS_FILENAME = "exec-approvals.json";
+const EXEC_APPROVALS_SOCKET_FILENAME = "exec-approvals.sock";

-export function resolveExecApprovalsPath(): string {
-  return expandHomePrefix(DEFAULT_FILE);
+export function resolveExecApprovalsPath(env: NodeJS.ProcessEnv = process.env): string {
+  return path.join(resolveStateDir(env), EXEC_APPROVALS_FILENAME);
 }

(same shape for the socket helper)

When OPENCLAW_STATE_DIR is unset, resolveStateDir preserves the legacy fallback chain (existing ~/.openclaw, then ~/.clawdbot, then the default new ~/.openclaw), so existing installs see no behavior change.

The two resolver functions now accept an optional env parameter (defaulting to process.env), which keeps every existing call site working unchanged — there are 13 internal callers across exec-approvals.ts, plus the test surfaces in invoke-system-run.test.ts and exec-approvals-store.test.ts. None of them needed to change.

Backward compatibility

ScenarioBeforeAfter
No env override<home>/.openclaw/exec-approvals.jsonsame
OPENCLAW_STATE_DIR=/foo<home>/.openclaw/exec-approvals.json (split state)/foo/exec-approvals.json (unified)
OPENCLAW_HOME=/h, no state-dir/h/.openclaw/exec-approvals.jsonsame
Legacy ~/.clawdbot exists, no env override<home>/.openclaw/exec-approvals.json<home>/.clawdbot/exec-approvals.json (now follows the same legacy detection as every other artifact — note: this only flips when ~/.openclaw doesn't exist yet)

The legacy-detection delta is intentional alignment with the rest of the codebase. In practice, every install path creates ~/.openclaw before exec-approvals are ever written, so this doesn't change the on-disk location in normal operation.

Test plan

  • New regression test exec-approvals-store.test.ts — "honors OPENCLAW_STATE_DIR for the file and socket paths (regression for #75204)". Sets OPENCLAW_STATE_DIR to a separate dir from OPENCLAW_HOME and asserts both file and socket paths resolve under the configured state dir.
  • Existing test still passes — "expands home-prefixed default file and socket paths" sets only OPENCLAW_HOME. With the override absent, resolveStateDir returns <home>/.openclaw, matching the existing assertion.
  • Existing afterEach now also cleans up OPENCLAW_STATE_DIR between tests so the new case can't leak into siblings.

Why this is the smallest fix that resolves the issue

The bug is two hardcoded constants. The state-dir resolver already exists, is well-tested, and handles every edge case (env override, home-relative expansion, legacy directory detection, Nix mode, the OPENCLAW_HOME interaction). The fix is to call it. Every alternative — adding a per-helper env-var lookup, exposing a new wrapper, extending expandHomePrefix — would be more code for the same outcome and would diverge from the codebase's standard pattern.

Changed files

  • src/infra/exec-approvals-store.test.ts (modified, +24/-0)
  • src/infra/exec-approvals.ts (modified, +13/-6)

Code Example

export OPENCLAW_STATE_DIR="~/openclaw"

---

curl -fsSL https://openclaw.ai/install.sh | bash

---

State integrity ──────────────────────────────────────────────────────────────╮
│                                                                                │
- OAuth dir not present (~/openclaw/credentials). Skipping create because no  │
WhatsApp/pairing channel config is active.                                  
- Multiple state directories detected. This can split session history.        
- ~/.openclawActive state dir: ~/openclaw                                                │
│                                                                                │
├────────────────────────────────────────────────────────────────────────────────╯

---
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

No

Summary

In as installation with OPENCLAW_STATE_DIR set to ~/openclaw, the file exec-approvals.json is still stored in ~/.openclaw

Steps to reproduce

I performed a fresh install of OpenClaw 2024.04.27 on a Debian Trixie machine.

Before launching the install script, I set the OPENCLAW_STATE_DIR to "~/openclaw" using the command

export OPENCLAW_STATE_DIR="~/openclaw"

I also add it to the .bashrc command.

Then, I launched the command to install OC with the usual

curl -fsSL https://openclaw.ai/install.sh | bash

Setup a gateway, hatch the agent, etc.

Now, on my system I have both ~/openclaw and ~/.openclaw, and inside ~/.openclaw there is only one file exec-approvals.json (which is not present in ~/openclaw)

When openclaw doctor is launched, this problem is returned

◇  State integrity ──────────────────────────────────────────────────────────────╮
│                                                                                │
│  - OAuth dir not present (~/openclaw/credentials). Skipping create because no  │
│    WhatsApp/pairing channel config is active.                                  │
│  - Multiple state directories detected. This can split session history.        │
│    - ~/.openclaw                                                               │
│    Active state dir: ~/openclaw                                                │
│                                                                                │
├────────────────────────────────────────────────────────────────────────────────╯

Expected behavior

File in ~/openclaw/exec-approvals.json

Actual behavior

File in ~/.openclaw/exec-approvals.json

OpenClaw version

2026.4.27

Operating system

Debian Trixie

Install method

nmp global

Model

gemini-flast-latest

Provider / routing chain

openclaw -> google API -> gemini

Additional provider/model setup details

No response

Logs, screenshots, and evidence

Impact and severity

No response

Additional information

No response

extent analysis

TL;DR

The issue can likely be resolved by ensuring the OPENCLAW_STATE_DIR environment variable is correctly set and used by the OpenClaw installation script.

Guidance

  • Verify that the OPENCLAW_STATE_DIR environment variable is set to ~/openclaw before running the installation script, and that it is correctly expanded to the full path.
  • Check the installation script to see if it correctly uses the OPENCLAW_STATE_DIR environment variable to determine the state directory.
  • Consider setting the OPENCLAW_STATE_DIR environment variable in a way that ensures it is set for the installation script, such as using OPENCLAW_STATE_DIR=~/openclaw curl -fsSL https://openclaw.ai/install.sh | bash.
  • Investigate why the exec-approvals.json file is being written to ~/.openclaw instead of ~/openclaw, and adjust the configuration or script accordingly.

Example

No code snippet is provided as the issue does not require a specific code change.

Notes

The issue may be related to how the OPENCLAW_STATE_DIR environment variable is being set and used by the installation script. Further investigation is needed to determine the root cause.

Recommendation

Apply workaround: Set the OPENCLAW_STATE_DIR environment variable correctly before running the installation script, and verify that it is being used correctly by the script. This may resolve the issue without requiring an upgrade or code change.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

File in ~/openclaw/exec-approvals.json

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix [Bug]: exec-approvals.json file is stored in ~/.openclaw despite OPENCLAW_STATE_DIR is set to ~/openclaw [3 pull requests, 1 comments, 2 participants]