diff --git a/src/ui/React/RecoveryRoot.tsx b/src/ui/React/RecoveryRoot.tsx index f9b1bc5c8..536c0115a 100644 --- a/src/ui/React/RecoveryRoot.tsx +++ b/src/ui/React/RecoveryRoot.tsx @@ -5,7 +5,7 @@ import { Settings } from "../../Settings/Settings"; import { load } from "../../db"; import { Router } from "../GameRoot"; import { Page } from "../Router"; -import { IErrorData, newIssueUrl } from "../../utils/ErrorHelper"; +import { IErrorData, newIssueUrl, getErrorForDisplay } from "../../utils/ErrorHelper"; import { DeleteGameButton } from "./DeleteGameButton"; import { SoftResetButton } from "./SoftResetButton"; @@ -38,6 +38,13 @@ export function RecoveryRoot({ softReset, errorData, resetError }: IProps): Reac } Settings.AutosaveInterval = 0; + // The architecture around RecoveryRoot is awkward, and it can be invoked in + // a number of ways. If we are invoked via a save error, sourceError will be set + // and we won't have decoded the information into errorData. + if (errorData == null && sourceError) { + errorData = getErrorForDisplay(sourceError, undefined, Page.LoadingScreen); + } + useEffect(() => { load() .then((content) => { diff --git a/src/utils/ErrorHelper.ts b/src/utils/ErrorHelper.ts index 5c0a21d9b..61279a3a1 100644 --- a/src/utils/ErrorHelper.ts +++ b/src/utils/ErrorHelper.ts @@ -30,7 +30,7 @@ interface BrowserFeatures { } interface IErrorMetadata { - error: Error; + error: Record; errorInfo?: React.ErrorInfo; page?: Page; @@ -54,7 +54,7 @@ export interface IErrorData { export const newIssueUrl = `https://github.com/bitburner-official/bitburner-src/issues/new`; -function getErrorMetadata(error: Error, errorInfo?: React.ErrorInfo, page?: Page): IErrorMetadata { +function getErrorMetadata(error: unknown, errorInfo?: React.ErrorInfo, page?: Page): IErrorMetadata { const isElectron = navigator.userAgent.toLowerCase().includes(" electron/"); const env = process.env.NODE_ENV === "development" ? GameEnv.Development : GameEnv.Production; const version: GameVersion = { @@ -70,19 +70,20 @@ function getErrorMetadata(error: Error, errorInfo?: React.ErrorInfo, page?: Page doNotTrack: navigator.doNotTrack, indexedDb: !!window.indexedDB, }; + const errorObj = typeof error === "object" && error !== null ? (error as Record) : {}; const metadata: IErrorMetadata = { platform: isElectron ? Platform.Steam : Platform.Browser, environment: env, version, features, - error, + error: errorObj, errorInfo, page, }; return metadata; } -export function getErrorForDisplay(error: Error, errorInfo?: React.ErrorInfo, page?: Page): IErrorData { +export function getErrorForDisplay(error: unknown, errorInfo?: React.ErrorInfo, page?: Page): IErrorData { const metadata = getErrorMetadata(error, errorInfo, page); const fileName = (metadata.error as any).fileName; const features = @@ -112,16 +113,11 @@ Please fill this information with details if relevant. * Features: ${features} * Source: ${fileName ?? "n/a"} -${ - metadata.environment === GameEnv.Development - ? ` ### Stack Trace \`\`\` -${metadata.errorInfo?.componentStack.toString().trim()} +${metadata.error.stack} \`\`\` -` - : "" -} + ### Save \`\`\` Copy your save here if possible