diff --git a/src/core/AnonymousError.ts b/src/core/AnonymousError.ts index 40c40a8..392c0e9 100644 --- a/src/core/AnonymousError.ts +++ b/src/core/AnonymousError.ts @@ -27,21 +27,37 @@ export default class AnonymousError extends CustomError { this.cause = opt?.cause; } - toString(): string { - let out = ""; - let detail = this.value ? JSON.stringify(this.value) : null; - if (this.value instanceof Repository) { - detail = this.value.repoId; - } else if (this.value instanceof AnonymizedFile) { - detail = `/r/${this.value.repository.repoId}/${this.value.anonymizedPath}`; - } else if (this.value instanceof GitHubRepository) { - detail = `${this.value.fullName}`; - } else if (this.value instanceof User) { - detail = `${this.value.username}`; - } else if (this.value instanceof GitHubBase) { - detail = `GHDownload ${this.value.data.repoId}`; + detail(): string | undefined { + if (this.value == null) return undefined; + try { + if (this.value instanceof Repository) return this.value.repoId; + if (this.value instanceof AnonymizedFile) { + const repoId = this.value.repository?.repoId; + // anonymizedPath getter can throw if the file isn't initialized; + // fall back to whatever path is known. + let p: string | undefined; + try { + p = this.value.anonymizedPath; + } catch { + p = this.value.filePath; + } + return repoId ? `/r/${repoId}/${p ?? ""}` : p; + } + if (this.value instanceof GitHubRepository) return this.value.fullName; + if (this.value instanceof User) return this.value.username; + if (this.value instanceof GitHubBase) { + return `GHDownload ${this.value.data.repoId}`; + } + if (typeof this.value === "string") return this.value; + return JSON.stringify(this.value); + } catch { + return String(this.value); } - out += this.message; + } + + toString(): string { + let out = this.message; + const detail = this.detail(); if (detail) { out += `: ${detail}`; } diff --git a/src/core/logger.ts b/src/core/logger.ts index a14590e..dfbcc99 100644 --- a/src/core/logger.ts +++ b/src/core/logger.ts @@ -140,6 +140,7 @@ type ErrorLike = { cause?: unknown; request?: { url?: string; method?: string }; response?: { url?: string; status?: number }; + detail?: () => string | undefined; }; export function serializeError(err: unknown): Record { @@ -161,6 +162,14 @@ export function serializeError(err: unknown): Record { // AnonymousError carries an httpStatus and an inner cause. if (typeof e.httpStatus === "number") out.httpStatus = e.httpStatus; if (e.code !== undefined && e.code !== e.message) out.code = e.code; + if (typeof e.detail === "function") { + try { + const d = e.detail(); + if (d) out.detail = d; + } catch { + /* ignore */ + } + } if (e.cause) out.cause = serializeError(e.cause); // Only include the stack when there's nothing else useful — avoids dumping