Improved StackAssertionError error logging

This commit is contained in:
Konstantin Wohlwend 2026-05-07 11:12:34 -07:00
parent ff01ca8c04
commit 7acbd8d56d
9 changed files with 14 additions and 12 deletions

View File

@ -403,3 +403,6 @@ A: `packages/template/vitest.config.ts` installs a Vite transform plugin for Vit
## Q: How does the Mintlify apps sidebar filter stay in sync with theme changes?
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.
## Q: How should `StackAssertionError` preserve an underlying thrown error?
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.

View File

@ -26,7 +26,6 @@ function captureOAuthAccessTokenRefreshIssue(options: {
attempts: options.refreshError.attempts,
retryCount: options.refreshError.retryCount,
sawAmbiguousRefreshAttempt: options.refreshError.sawAmbiguousRefreshAttempt,
error: options.refreshError.cause,
causes: options.refreshError.causes,
},
));
@ -197,7 +196,7 @@ export async function retrieveOrRefreshAccessToken(options: {
refreshError: tokenSetResult.error,
});
const assertionError = new StackAssertionError('Unexpected error refreshing access token — this may indicate a bug or misconfiguration', {
error: tokenSetResult.error.cause,
cause: tokenSetResult.error.cause,
providerClass: providerInstance.constructor.name,
refreshErrorType: tokenSetResult.error.type,
attempts: tokenSetResult.error.attempts,
@ -210,7 +209,7 @@ export async function retrieveOrRefreshAccessToken(options: {
}
default: {
const _: never = tokenSetResult.error;
throw new StackAssertionError("Unhandled OAuth access token refresh error", { error: _ });
throw new StackAssertionError("Unhandled OAuth access token refresh error", { cause: _ });
}
}
}

View File

@ -882,7 +882,7 @@ export const usersCrudHandlers = createLazyProxy(() => createCrudHandlers(usersC
}
});
throw new StackAssertionError("Failed to update team member", {
error: e,
cause: e,
tenancy_id: auth.tenancy.id,
user_id: params.user_id,
team_id: data.selected_team_id,

View File

@ -154,7 +154,7 @@ export async function renderEmailWithTemplate(
// This can happen with complex or invalid JSX
captureError("email-transpilation-template-error", new StackAssertionError(
"Failed to transpile template for editable markers",
{ error: e instanceof Error ? e.message : String(e) }
{ cause: e }
));
}
}
@ -169,7 +169,7 @@ export async function renderEmailWithTemplate(
// If transpilation fails, fall back to original source
captureError("email-transpilation-theme-error", new StackAssertionError(
"Failed to transpile theme for editable markers",
{ error: e instanceof Error ? e.message : String(e) }
{ cause: e }
));
}
}

View File

@ -247,7 +247,7 @@ export async function logEvent<T extends EventType[]>(
data = await eventType.dataSchema.validate(data, { strict: true, stripUnknown: false });
} catch (error) {
if (error instanceof yup.ValidationError) {
throw new StackAssertionError(`Invalid event data for event type: ${eventType.id}`, { eventType, data, error, originalData, originalEventTypes: eventTypes, cause: error });
throw new StackAssertionError(`Invalid event data for event type: ${eventType.id}`, { eventType, data, originalData, originalEventTypes: eventTypes, cause: error });
}
throw error;
}

View File

@ -236,7 +236,7 @@ async function runWithFallback(code: string, options: ExecuteJavascriptOptions):
captureError(`js-execution-freestyle-failed`, new StackAssertionError(
`JS execution freestyle engine failed, falling back to vercel sandbox engine`,
{ error: retryResult.error, innerCode: code, innerOptions: options }
{ cause: retryResult.error, innerCode: code, innerOptions: options }
));
try {
@ -245,7 +245,7 @@ async function runWithFallback(code: string, options: ExecuteJavascriptOptions):
} catch (error){
captureError(`js-execution-vercel-sandbox-failed`, new StackAssertionError(
`JS execution vercel sandbox engine failed after fallback from freestyle engine`,
{ error: error, innerCode: code, innerOptions: options }
{ cause: error, innerCode: code, innerOptions: options }
));
throw new StackAssertionError("Vercel Sandbox service unavailable", { cause: error, innerCode: code, innerOptions: options });
}

View File

@ -104,7 +104,7 @@ export async function resolveProductFromStripeMetadata(options: {
tenancyId: options.tenancyId,
productString,
metadata: options.metadata,
error,
cause: error,
}
);
}

View File

@ -35,7 +35,7 @@ export class AppleProvider extends OAuthBaseProvider {
try {
payload = decodeJwt(idToken);
} catch (error) {
throw new StackAssertionError("Error decoding Apple ID token", { error });
throw new StackAssertionError("Error decoding Apple ID token", { cause: error });
}
return validateUserInfo({

View File

@ -1562,7 +1562,7 @@ export class StackClientInterface {
// refresh token was already invalid, just continue like nothing happened
} else {
// this should never happen
throw new StackAssertionError("Unexpected error", { error: resOrError.error });
throw new StackAssertionError("Unexpected error", { cause: resOrError.error });
}
} else {
// user was signed out successfully, all good