fix(runtime): throw typed ExitError instead of generic Error for simulated exit (#97796)#97803
Merged
openclaw-clownfish[bot] merged 1 commit intoJul 6, 2026
Conversation
This comment has been minimized.
This comment has been minimized.
maweibin
force-pushed
the
fix/exit-error-typed-class-97796
branch
2 times, most recently
from
June 29, 2026 14:25
b320656 to
4cc553d
Compare
…lated exit (openclaw#97796) createNonExitingRuntime.exit() threw a generic Error, making it impossible for upstream try-catch to distinguish a simulated process exit from a real runtime crash. Added an ExitError class (internal-only, not exported from SDK) that callers can check via instanceof. ExitError is kept internal to avoid expanding the public plugin SDK API surface without maintainer approval. Tests import directly from ./runtime.js. Fixes openclaw#97796. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
maweibin
force-pushed
the
fix/exit-error-typed-class-97796
branch
from
June 29, 2026 15:16
4cc553d to
2669115
Compare
Contributor
Author
|
@clawsweeper re-review |
Contributor
|
🦞🧹 I asked ClawSweeper to review this item again. |
This was referenced Jun 29, 2026
Closed
This was referenced Jun 30, 2026
Contributor
Author
Merge ReadinessTyped
@cpojer @CharlesDusek — small runtime contract improvement, ready for review. |
Member
|
No description provided. |
openclaw-clownfish
Bot
merged commit Jul 6, 2026
5861070
into
openclaw:main
124 of 129 checks passed
github-actions Bot
pushed a commit
to Desicool/openclaw
that referenced
this pull request
Jul 7, 2026
…lated exit (openclaw#97796) (openclaw#97803) createNonExitingRuntime.exit() threw a generic Error, making it impossible for upstream try-catch to distinguish a simulated process exit from a real runtime crash. Added an ExitError class (internal-only, not exported from SDK) that callers can check via instanceof. ExitError is kept internal to avoid expanding the public plugin SDK API surface without maintainer approval. Tests import directly from ./runtime.js. Fixes openclaw#97796. Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
giodl73-repo
pushed a commit
to giodl73-repo/openclaw
that referenced
this pull request
Jul 8, 2026
…lated exit (openclaw#97796) (openclaw#97803) createNonExitingRuntime.exit() threw a generic Error, making it impossible for upstream try-catch to distinguish a simulated process exit from a real runtime crash. Added an ExitError class (internal-only, not exported from SDK) that callers can check via instanceof. ExitError is kept internal to avoid expanding the public plugin SDK API surface without maintainer approval. Tests import directly from ./runtime.js. Fixes openclaw#97796. Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
maweibin
added a commit
to maweibin/openclaw
that referenced
this pull request
Jul 10, 2026
…eric Error
Replace generic Error throws in facade-loader with MissingPublicSurfaceError
so callers can use instanceof to distinguish missing optional artifacts from
real runtime errors.
Before: throw new Error('Unable to resolve...') — callers match via
fragile error.message.startsWith(MISSING_PUBLIC_SURFACE_PREFIX)
After: throw new MissingPublicSurfaceError('Unable to resolve...') —
callers can use error instanceof MissingPublicSurfaceError
MissingPublicSurfaceError is kept internal (not re-exported from public
plugin SDK subpaths), matching the ExitError pattern in openclaw#97803.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #97796.
What Problem This Solves
createNonExitingRuntime().exit()throws a genericError, making it impossible for upstreamtry-catchhandlers to distinguish a simulated process exit from a real runtime crash. Any code that needs to handle "exit requested but we're in a non-exiting runtime" differently from an actual error has no clean way to do so.Why This Change Was Made
Added an internal
ExitErrorclass (extendingError) that is thrown bycreateNonExitingRuntime().exit()instead of a genericError. Callers can now useinstanceof ExitErrorto distinguish simulated exits from real errors.ExitErroris intentionally kept internal — it is exported fromsrc/runtime.tsfor direct test imports, but is not re-exported from the public plugin SDK subpaths (plugin-sdk/runtime.ts,plugin-sdk/runtime-env.ts). This avoids expanding the public plugin SDK API surface without maintainer approval.User Impact
No user-facing impact. This is an internal runtime improvement for code that uses
createNonExitingRuntime.Evidence
Behavior addressed:
createNonExitingRuntime().exit()throws genericError— no way to distinguish simulated exit from runtime crash.Real environment tested: Node 24.13.1, local OpenClaw checkout.
Exact steps or command run after this patch:
Evidence after fix:
Before fix:
e instanceof Erroris true but there's no way to know it's an exit vs a crash.After fix:
e instanceof ExitErrorcleanly distinguishes the two.exit function throws ExitError— verifies typed error is thrownExitError includes exit code— verifies code is preserved in message and instanceofExitError is distinguishable from generic Error— NEW: proves instanceof ExitError works independently of instanceof ErrorObserved result after fix:
createNonExitingRuntime().exit()throwsExitErrorwith the exit code and a descriptive message. Callers can useinstanceof ExitErrorto distinguish simulated exits from real errors.What was not tested: Upstream callers that currently catch the generic
Errorand would benefit from switching toinstanceof ExitError. Those are follow-up work and not part of this change.Regression Test Plan
node scripts/run-vitest.mjs src/runtime.test.ts --run— Test Files 1 passed (1), Tests 8 passed (8)node scripts/run-oxlint.mjs src/runtime.ts src/runtime.test.ts— exit 0Root Cause
In
createNonExitingRuntime(), theexitfunction throwsnew Error(\exit ${code}`)— a genericErrorinstance. Any upstream code that catches errors from the runtime cannot distinguish "the runtime simulated process.exit" from "something actually crashed." The fix adds a typedExitErrorsubclass so callers can useinstanceof` checks for clean control flow.AI Assistance