summaryrefslogtreecommitdiff
path: root/packages/backend/src/misc
diff options
context:
space:
mode:
authorHazelnoot <acomputerdog@gmail.com>2025-05-22 12:27:54 -0400
committerHazelnoot <acomputerdog@gmail.com>2025-06-06 22:20:17 -0400
commit2cba0ada3cdf6b7ee37fa5c0b54134160be657a9 (patch)
tree38f6b59f7c60eda90677bc178974f71c877afe0d /packages/backend/src/misc
parentrender error cause in render-inline-error.ts (diff)
downloadsharkey-2cba0ada3cdf6b7ee37fa5c0b54134160be657a9.tar.gz
sharkey-2cba0ada3cdf6b7ee37fa5c0b54134160be657a9.tar.bz2
sharkey-2cba0ada3cdf6b7ee37fa5c0b54134160be657a9.zip
more use of identifiable errors, improvements to inner error rendering, and more heuristics for is-retryable-error
Diffstat (limited to 'packages/backend/src/misc')
-rw-r--r--packages/backend/src/misc/FileWriterStream.ts2
-rw-r--r--packages/backend/src/misc/fastify-reply-error.ts4
-rw-r--r--packages/backend/src/misc/id/aid.ts3
-rw-r--r--packages/backend/src/misc/id/aidx.ts3
-rw-r--r--packages/backend/src/misc/identifiable-error.ts4
-rw-r--r--packages/backend/src/misc/is-retryable-error.ts12
-rw-r--r--packages/backend/src/misc/render-inline-error.ts50
-rw-r--r--packages/backend/src/misc/status-error.ts4
8 files changed, 60 insertions, 22 deletions
diff --git a/packages/backend/src/misc/FileWriterStream.ts b/packages/backend/src/misc/FileWriterStream.ts
index 27c67cb5df..a61d949ef4 100644
--- a/packages/backend/src/misc/FileWriterStream.ts
+++ b/packages/backend/src/misc/FileWriterStream.ts
@@ -21,7 +21,7 @@ export class FileWriterStream extends WritableStream<Uint8Array> {
write: async (chunk, controller) => {
if (file === null) {
controller.error();
- throw new Error();
+ throw new Error('file is null');
}
await file.write(chunk);
diff --git a/packages/backend/src/misc/fastify-reply-error.ts b/packages/backend/src/misc/fastify-reply-error.ts
index e6c4e78d2f..03109e8b96 100644
--- a/packages/backend/src/misc/fastify-reply-error.ts
+++ b/packages/backend/src/misc/fastify-reply-error.ts
@@ -8,8 +8,8 @@ export class FastifyReplyError extends Error {
public message: string;
public statusCode: number;
- constructor(statusCode: number, message: string) {
- super(message);
+ constructor(statusCode: number, message: string, cause?: unknown) {
+ super(message, cause ? { cause } : undefined);
this.message = message;
this.statusCode = statusCode;
}
diff --git a/packages/backend/src/misc/id/aid.ts b/packages/backend/src/misc/id/aid.ts
index c0e8478db5..f0eba2d99c 100644
--- a/packages/backend/src/misc/id/aid.ts
+++ b/packages/backend/src/misc/id/aid.ts
@@ -8,6 +8,7 @@
import * as crypto from 'node:crypto';
import { parseBigInt36 } from '@/misc/bigint.js';
+import { IdentifiableError } from '../identifiable-error.js';
export const aidRegExp = /^[0-9a-z]{10}$/;
@@ -26,7 +27,7 @@ function getNoise(): string {
}
export function genAid(t: number): string {
- if (isNaN(t)) throw new Error('Failed to create AID: Invalid Date');
+ if (isNaN(t)) throw new IdentifiableError('6b73b7d5-9d2b-48b4-821c-ef955efe80ad', 'Failed to create AID: Invalid Date');
counter++;
return getTime(t) + getNoise();
}
diff --git a/packages/backend/src/misc/id/aidx.ts b/packages/backend/src/misc/id/aidx.ts
index 006673a6d0..d2bb566e35 100644
--- a/packages/backend/src/misc/id/aidx.ts
+++ b/packages/backend/src/misc/id/aidx.ts
@@ -10,6 +10,7 @@
import { customAlphabet } from 'nanoid';
import { parseBigInt36 } from '@/misc/bigint.js';
+import { IdentifiableError } from '../identifiable-error.js';
export const aidxRegExp = /^[0-9a-z]{16}$/;
@@ -34,7 +35,7 @@ function getNoise(): string {
}
export function genAidx(t: number): string {
- if (isNaN(t)) throw new Error('Failed to create AIDX: Invalid Date');
+ if (isNaN(t)) throw new IdentifiableError('6b73b7d5-9d2b-48b4-821c-ef955efe80ad', 'Failed to create AIDX: Invalid Date');
counter++;
return getTime(t) + nodeId + getNoise();
}
diff --git a/packages/backend/src/misc/identifiable-error.ts b/packages/backend/src/misc/identifiable-error.ts
index 33ee7c3f25..56e13f2622 100644
--- a/packages/backend/src/misc/identifiable-error.ts
+++ b/packages/backend/src/misc/identifiable-error.ts
@@ -15,8 +15,8 @@ export class IdentifiableError extends Error {
*/
public readonly isRetryable: boolean;
- constructor(id: string, message?: string, isRetryable = false, options?: ErrorOptions) {
- super(message, options);
+ constructor(id: string, message?: string, isRetryable = false, cause?: unknown) {
+ super(message, cause ? { cause } : undefined);
this.message = message ?? '';
this.id = id;
this.isRetryable = isRetryable;
diff --git a/packages/backend/src/misc/is-retryable-error.ts b/packages/backend/src/misc/is-retryable-error.ts
index ed2a7ebee3..63b561b280 100644
--- a/packages/backend/src/misc/is-retryable-error.ts
+++ b/packages/backend/src/misc/is-retryable-error.ts
@@ -7,14 +7,26 @@ import { AbortError, FetchError } from 'node-fetch';
import { UnrecoverableError } from 'bullmq';
import { StatusError } from '@/misc/status-error.js';
import { IdentifiableError } from '@/misc/identifiable-error.js';
+import { CaptchaError, captchaErrorCodes } from '@/core/CaptchaService.js';
+import { FastifyReplyError } from '@/misc/fastify-reply-error.js';
+import { ConflictError } from '@/server/SkRateLimiterService.js';
/**
* Returns false if the provided value represents a "permanent" error that cannot be retried.
* Returns true if the error is retryable, unknown (as all errors are retryable by default), or not an error object.
*/
export function isRetryableError(e: unknown): boolean {
+ if (e instanceof AggregateError) return e.errors.every(inner => isRetryableError(inner));
if (e instanceof StatusError) return e.isRetryable;
if (e instanceof IdentifiableError) return e.isRetryable;
+ if (e instanceof CaptchaError) {
+ if (e.code === captchaErrorCodes.verificationFailed) return false;
+ if (e.code === captchaErrorCodes.invalidParameters) return false;
+ if (e.code === captchaErrorCodes.invalidProvider) return false;
+ return true;
+ }
+ if (e instanceof FastifyReplyError) return false;
+ if (e instanceof ConflictError) return true;
if (e instanceof UnrecoverableError) return false;
if (e instanceof AbortError) return true;
if (e instanceof FetchError) return true;
diff --git a/packages/backend/src/misc/render-inline-error.ts b/packages/backend/src/misc/render-inline-error.ts
index 3d1bd7746d..ccd4f524bc 100644
--- a/packages/backend/src/misc/render-inline-error.ts
+++ b/packages/backend/src/misc/render-inline-error.ts
@@ -5,23 +5,35 @@
import { IdentifiableError } from '@/misc/identifiable-error.js';
import { StatusError } from '@/misc/status-error.js';
+import { CaptchaError } from '@/core/CaptchaService.js';
export function renderInlineError(err: unknown): string {
- if (err instanceof Error) {
- const text = printError(err);
+ const parts: string[] = [];
+ renderTo(err, parts);
+ return parts.join('');
+}
- if (err.cause) {
- const cause = renderInlineError(err.cause);
- return `${text} [caused by]: ${cause}`;
- } else {
- return text;
+function renderTo(err: unknown, parts: string[]): void {
+ parts.push(printError(err));
+
+ if (err instanceof AggregateError) {
+ for (let i = 0; i < err.errors.length; i++) {
+ parts.push(` [${i + 1}/${err.errors.length}]: `);
+ renderTo(err.errors[i], parts);
}
}
- return String(err);
+ if (err instanceof Error) {
+ if (err.cause) {
+ parts.push(' [caused by]: ');
+ renderTo(err.cause, parts);
+ // const cause = renderInlineError(err.cause);
+ // parts.push(' [caused by]: ', cause);
+ }
+ }
}
-function printError(err: Error): string {
+function printError(err: unknown): string {
if (err instanceof IdentifiableError) {
if (err.message) {
return `${err.name} ${err.id}: ${err.message}`;
@@ -40,9 +52,21 @@ function printError(err: Error): string {
}
}
- if (err.message) {
- return `${err.name}: ${err.message}`;
- } else {
- return err.name;
+ if (err instanceof CaptchaError) {
+ if (err.code.description) {
+ return `${err.name} ${err.code.description}: ${err.message}`;
+ } else {
+ return `${err.name}: ${err.message}`;
+ }
+ }
+
+ if (err instanceof Error) {
+ if (err.message) {
+ return `${err.name}: ${err.message}`;
+ } else {
+ return err.name;
+ }
}
+
+ return String(err);
}
diff --git a/packages/backend/src/misc/status-error.ts b/packages/backend/src/misc/status-error.ts
index 2c70d28f8d..4fd3bfcafb 100644
--- a/packages/backend/src/misc/status-error.ts
+++ b/packages/backend/src/misc/status-error.ts
@@ -9,8 +9,8 @@ export class StatusError extends Error {
public isClientError: boolean;
public isRetryable: boolean;
- constructor(message: string, statusCode: number, statusMessage?: string, options?: ErrorOptions) {
- super(message, options);
+ constructor(message: string, statusCode: number, statusMessage?: string, cause?: unknown) {
+ super(message, cause ? { cause } : undefined);
this.name = 'StatusError';
this.statusCode = statusCode;
this.statusMessage = statusMessage;