Skip to content

Commit 7acbd8d

Browse files
committed
Improved StackAssertionError error logging
1 parent ff01ca8 commit 7acbd8d

9 files changed

Lines changed: 14 additions & 12 deletions

File tree

.claude/CLAUDE-KNOWLEDGE.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,3 +403,6 @@ A: `packages/template/vitest.config.ts` installs a Vite transform plugin for Vit
403403

404404
## Q: How does the Mintlify apps sidebar filter stay in sync with theme changes?
405405
A: `docs-mintlify/apps-sidebar-filter.js` injects the Apps filter with inline styles, so the MutationObserver must reapply `applySidebarAppsFilterTheme` when an existing input is found. Theme detection should handle both `html.dark` and `data-theme="dark"` signals.
406+
407+
## Q: How should `StackAssertionError` preserve an underlying thrown error?
408+
A: Pass the underlying error as the `cause` property in the second argument. The `StackAssertionError` constructor only forwards `cause` into `ErrorOptions`, so storing a caught error under an `error` property captures it as ordinary metadata instead of preserving the error cause chain.

apps/backend/src/app/api/latest/connected-accounts/access-token-helpers.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ function captureOAuthAccessTokenRefreshIssue(options: {
2626
attempts: options.refreshError.attempts,
2727
retryCount: options.refreshError.retryCount,
2828
sawAmbiguousRefreshAttempt: options.refreshError.sawAmbiguousRefreshAttempt,
29-
error: options.refreshError.cause,
3029
causes: options.refreshError.causes,
3130
},
3231
));
@@ -197,7 +196,7 @@ export async function retrieveOrRefreshAccessToken(options: {
197196
refreshError: tokenSetResult.error,
198197
});
199198
const assertionError = new StackAssertionError('Unexpected error refreshing access token — this may indicate a bug or misconfiguration', {
200-
error: tokenSetResult.error.cause,
199+
cause: tokenSetResult.error.cause,
201200
providerClass: providerInstance.constructor.name,
202201
refreshErrorType: tokenSetResult.error.type,
203202
attempts: tokenSetResult.error.attempts,
@@ -210,7 +209,7 @@ export async function retrieveOrRefreshAccessToken(options: {
210209
}
211210
default: {
212211
const _: never = tokenSetResult.error;
213-
throw new StackAssertionError("Unhandled OAuth access token refresh error", { error: _ });
212+
throw new StackAssertionError("Unhandled OAuth access token refresh error", { cause: _ });
214213
}
215214
}
216215
}

apps/backend/src/app/api/latest/users/crud.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -882,7 +882,7 @@ export const usersCrudHandlers = createLazyProxy(() => createCrudHandlers(usersC
882882
}
883883
});
884884
throw new StackAssertionError("Failed to update team member", {
885-
error: e,
885+
cause: e,
886886
tenancy_id: auth.tenancy.id,
887887
user_id: params.user_id,
888888
team_id: data.selected_team_id,

apps/backend/src/lib/email-rendering.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ export async function renderEmailWithTemplate(
154154
// This can happen with complex or invalid JSX
155155
captureError("email-transpilation-template-error", new StackAssertionError(
156156
"Failed to transpile template for editable markers",
157-
{ error: e instanceof Error ? e.message : String(e) }
157+
{ cause: e }
158158
));
159159
}
160160
}
@@ -169,7 +169,7 @@ export async function renderEmailWithTemplate(
169169
// If transpilation fails, fall back to original source
170170
captureError("email-transpilation-theme-error", new StackAssertionError(
171171
"Failed to transpile theme for editable markers",
172-
{ error: e instanceof Error ? e.message : String(e) }
172+
{ cause: e }
173173
));
174174
}
175175
}

apps/backend/src/lib/events.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ export async function logEvent<T extends EventType[]>(
247247
data = await eventType.dataSchema.validate(data, { strict: true, stripUnknown: false });
248248
} catch (error) {
249249
if (error instanceof yup.ValidationError) {
250-
throw new StackAssertionError(`Invalid event data for event type: ${eventType.id}`, { eventType, data, error, originalData, originalEventTypes: eventTypes, cause: error });
250+
throw new StackAssertionError(`Invalid event data for event type: ${eventType.id}`, { eventType, data, originalData, originalEventTypes: eventTypes, cause: error });
251251
}
252252
throw error;
253253
}

apps/backend/src/lib/js-execution.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ async function runWithFallback(code: string, options: ExecuteJavascriptOptions):
236236

237237
captureError(`js-execution-freestyle-failed`, new StackAssertionError(
238238
`JS execution freestyle engine failed, falling back to vercel sandbox engine`,
239-
{ error: retryResult.error, innerCode: code, innerOptions: options }
239+
{ cause: retryResult.error, innerCode: code, innerOptions: options }
240240
));
241241

242242
try {
@@ -245,7 +245,7 @@ async function runWithFallback(code: string, options: ExecuteJavascriptOptions):
245245
} catch (error){
246246
captureError(`js-execution-vercel-sandbox-failed`, new StackAssertionError(
247247
`JS execution vercel sandbox engine failed after fallback from freestyle engine`,
248-
{ error: error, innerCode: code, innerOptions: options }
248+
{ cause: error, innerCode: code, innerOptions: options }
249249
));
250250
throw new StackAssertionError("Vercel Sandbox service unavailable", { cause: error, innerCode: code, innerOptions: options });
251251
}

apps/backend/src/lib/stripe.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ export async function resolveProductFromStripeMetadata(options: {
104104
tenancyId: options.tenancyId,
105105
productString,
106106
metadata: options.metadata,
107-
error,
107+
cause: error,
108108
}
109109
);
110110
}

apps/backend/src/oauth/providers/apple.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export class AppleProvider extends OAuthBaseProvider {
3535
try {
3636
payload = decodeJwt(idToken);
3737
} catch (error) {
38-
throw new StackAssertionError("Error decoding Apple ID token", { error });
38+
throw new StackAssertionError("Error decoding Apple ID token", { cause: error });
3939
}
4040

4141
return validateUserInfo({

packages/stack-shared/src/interface/client-interface.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1562,7 +1562,7 @@ export class StackClientInterface {
15621562
// refresh token was already invalid, just continue like nothing happened
15631563
} else {
15641564
// this should never happen
1565-
throw new StackAssertionError("Unexpected error", { error: resOrError.error });
1565+
throw new StackAssertionError("Unexpected error", { cause: resOrError.error });
15661566
}
15671567
} else {
15681568
// user was signed out successfully, all good

0 commit comments

Comments
 (0)