Skip to content

fix: resolve symlinks in session path validation (#18553)#18593

Closed
EpaL wants to merge 1 commit intoopenclaw:mainfrom
EpaL:fix/session-path-symlink-resolution
Closed

fix: resolve symlinks in session path validation (#18553)#18593
EpaL wants to merge 1 commit intoopenclaw:mainfrom
EpaL:fix/session-path-symlink-resolution

Conversation

@EpaL
Copy link

@EpaL EpaL commented Feb 16, 2026

Problem

When the OpenClaw state directory is accessed through a symlink (e.g. ~/.clawdbot -> ~/.openclaw after the rename migration), session file paths stored with the old symlink prefix fail the containment check in resolvePathWithinSessionsDir.

path.relative() does not follow symlinks, so a stored path like:

/Users/foo/.clawdbot/agents/main/sessions/abc.jsonl

computed relative to:

/Users/foo/.openclaw/agents/main/sessions/

produces ../../../../.clawdbot/agents/main/sessions/abc.jsonl (starts with ..), which fails validation even though both paths resolve to the same physical file.

Impact

  • doctor --fix crashes after applying config migrations
  • Discord guild message handler crashes on every inbound message — bots can send to channels but cannot receive
  • Any code path that resolves stored sessionFile paths fails

Root cause

The .clawdbot.openclaw migration left a compatibility symlink, but resolvePathWithinSessionsDir and resolvePathFromAgentSessionsDir use path.resolve() which does not follow symlinks.

Fix

Use fs.realpathSync() to resolve symlinks on both the base sessions directory and the candidate path before computing the relative path. A new safeRealpathSync() helper falls back gracefully if the path does not exist yet.

Testing

  • Verified on a real system with .clawdbot -> .openclaw symlink
  • 6 stale session entries with old paths now resolve correctly
  • Discord guild message handler no longer crashes
  • doctor --fix completes without error

Fixes #18553

Greptile Summary

This PR fixes session path validation failures caused by symlinks (e.g., ~/.clawdbot → ~/.openclaw) by using fs.realpathSync to resolve symlinks on both the base directory and candidate paths before computing relative paths. A new safeRealpathSync helper gracefully falls back when paths don't exist yet. The fix is applied consistently in both resolvePathFromAgentSessionsDir and resolvePathWithinSessionsDir.

Confidence Score: 3/5

  • The symlink fix is correct but an unrelated structural fallback was removed, which may re-introduce a previously fixed regression.
  • The core fix (resolving symlinks via realpathSync) is sound and addresses the stated problem. However, the removal of the structural fallback for OPENCLAW_STATE_DIR changes is a potential regression that could affect users in multi-agent setups where the state directory path changes. This lowers confidence from what would otherwise be a 4.
  • Pay close attention to src/config/sessions/paths.ts — specifically the removed structural fallback in resolvePathWithinSessionsDir around lines 164-170.

Last reviewed commit: fc68137

(2/5) Greptile learns from your feedback when you react with thumbs up/down!

…h-escape errors

When the OpenClaw state directory is accessed through a symlink (e.g.
~/.clawdbot -> ~/.openclaw after a rename/migration), session file paths
stored with the old symlink prefix fail the containment check in
resolvePathWithinSessionsDir because path.relative() does not follow
symlinks.

This causes:
- `doctor --fix` to crash after applying config migrations
- Discord guild message handler to crash on every inbound message
- Any code path that resolves stored sessionFile paths to fail

Fix: use fs.realpathSync() to resolve symlinks on both the base
sessions directory and the candidate path before computing the relative
path. Falls back gracefully if the path does not exist yet.

Fixes openclaw#18553
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fc68137e47

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +141 to +143
const realBase = safeRealpathSync(resolvedBase) ?? resolvedBase;
const realTrimmed = path.isAbsolute(trimmed) ? (safeRealpathSync(trimmed) ?? trimmed) : trimmed;
const normalized = path.isAbsolute(realTrimmed) ? path.relative(realBase, realTrimmed) : realTrimmed;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Handle missing symlinked transcripts without false escape

When sessionsDir is a symlink path (for example .clawdbot/.../sessions) and sessionFile is an absolute path under that same alias but the file does not exist yet (or was deleted), safeRealpathSync(trimmed) falls back to the unresolved symlink path while realBase is canonicalized to the target path. In this mixed form, path.relative(realBase, realTrimmed) incorrectly starts with .., so resolvePathWithinSessionsDir throws Session file path must be within sessions directory for a path that is actually inside the same sessions tree. This introduces crashes/failures on code paths that should tolerate missing transcripts (e.g. integrity checks or transcript recreation).

Useful? React with 👍 / 👎.

@steipete steipete closed this Feb 16, 2026
@steipete steipete reopened this Feb 17, 2026
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 file reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 17, 2026

Greptile encountered an error while reviewing this PR. Please reach out to support@greptile.com for assistance.

@openclaw-barnacle
Copy link

This pull request has been automatically marked as stale due to inactivity.
Please add updates or it will be closed.

@openclaw-barnacle openclaw-barnacle bot added stale Marked as stale due to inactivity and removed stale Marked as stale due to inactivity labels Feb 22, 2026
@vincentkoc
Copy link
Member

Deep-dive merge-readiness pass:

The symlink realpath direction looks correct and should stay. Before merge, please restore/retain the previously shipped structural fallback for state-dir drift (the behavior added to handle changed OPENCLAW_STATE_DIR roots), then add tests covering both:

  • symlinked state-dir path equivalence
  • different historic state roots still resolving safe agents/<id>/sessions/** paths

Current check is stale-failing, so rebase + full CI rerun is required.

Changelog guidance if merged: one ### Fixes entry for symlink-safe session path validation with single-author credit (Thanks @EpaL).

@vincentkoc
Copy link
Member

Merge checklist (must-have):

  • Rebase on current main.
  • Keep the symlink-safe realpath resolution logic.
  • Restore/retain the previously shipped structural fallback that accepts valid agents/<id>/sessions/** paths when state roots differ (state-dir drift case).
  • Add tests for both scenarios in the same PR:
    • symlink alias (~/.clawdbot -> ~/.openclaw)
    • historical state-root mismatch without symlink
  • Rerun full CI.

Changelog line (if merged):
- Sessions/Paths: resolve symlinked state-dir aliases when validating transcript paths while preserving safe cross-agent/session-root compatibility behavior. (#18593) Thanks @EpaL.

Credit note:
This is the first remaining PR specifically addressing symlink-path equivalence in this cluster.

@vincentkoc
Copy link
Member

Thanks for driving this symlink path edge case. Closing as superseded by #24657, which ships the symlink-safe session path validation plus regression coverage. If there is still an uncovered case, share it and we can reopen immediately.

@vincentkoc vincentkoc closed this Feb 23, 2026
@vincentkoc vincentkoc added dedupe:child Duplicate issue/PR child in dedupe cluster close:duplicate Closed as duplicate labels Feb 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

close:duplicate Closed as duplicate dedupe:child Duplicate issue/PR child in dedupe cluster size: XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

doctor --fix crashes with 'Session file path must be within sessions directory' after applying config migrations

3 participants