Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
dbce078
Base error code refactoring.
rkistner Jan 9, 2025
6ffdef5
First pass of replacing generic errors.
rkistner Jan 9, 2025
3e9d646
Update error checks.
rkistner Jan 9, 2025
5a6ad03
Some more error codes.
rkistner Jan 9, 2025
a3a7ffd
Refactor to use an enum for error codes.
rkistner Jan 10, 2025
f844758
Fix tests.
rkistner Jan 13, 2025
4ebee9a
Fix more tests.
rkistner Jan 13, 2025
0e928cb
POC of script to generate documentation for error codes.
rkistner Jan 13, 2025
295b013
Dockerfile fixes.
rkistner Jan 13, 2025
c5dba89
Merge remote-tracking branch 'origin/main' into error-codes
rkistner Jan 17, 2025
0834a1d
Update error code documentation.
rkistner Jan 17, 2025
33577bb
Error codes for connection config.
rkistner Jan 17, 2025
e7477ef
Tweak docs output.
rkistner Jan 17, 2025
fb09b2e
Fix error code.
rkistner Jan 17, 2025
5ff0300
Merge remote-tracking branch 'origin/main' into error-codes
rkistner Jan 21, 2025
f953795
More error coverage.
rkistner Jan 21, 2025
034af1c
Add a test-connection cli action.
rkistner Jan 21, 2025
0e4f320
Friendly errors for MongoDB test connection.
rkistner Jan 21, 2025
60ed649
Add permission checks for MongoDB connection test.
rkistner Jan 21, 2025
a4ab3e6
Add check for listCollections.
rkistner Jan 21, 2025
54a899f
Improved error for null bucket definitions.
rkistner Jan 21, 2025
a924a63
Fix error codes.
rkistner Jan 21, 2025
032d570
Remove unused error codes.
rkistner Jan 21, 2025
a0a4cbb
Add changesets.
rkistner Jan 21, 2025
50e5810
Add changeset for sync rules change.
rkistner Jan 21, 2025
297d709
Fix comments.
rkistner Jan 22, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/fast-taxis-rush.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@powersync/service-core': patch
'@powersync/service-image': patch
---

Add "test-connection" CLI command
5 changes: 5 additions & 0 deletions .changeset/neat-cycles-trade.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@powersync/service-sync-rules': patch
---

Improved error message for "null" bucket definitions.
5 changes: 5 additions & 0 deletions .changeset/tasty-lamps-remember.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@powersync/service-module-mongodb': patch
---

Improved error messages for "Test Connection".
17 changes: 17 additions & 0 deletions .changeset/wicked-tigers-eat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
'@powersync/service-module-postgres-storage': patch
'@powersync/service-module-mongodb-storage': patch
'@powersync/service-module-postgres': patch
'@powersync/service-rsocket-router': patch
'@powersync/service-errors': patch
'@powersync/service-module-mongodb': patch
'@powersync/service-core': patch
'@powersync/service-module-mysql': patch
'@powersync/service-sync-rules': patch
'@powersync/lib-service-postgres': patch
'@powersync/lib-services-framework': patch
'@powersync/lib-service-mongodb': patch
'@powersync/service-image': patch
---

Introduce standard error codes
1 change: 1 addition & 0 deletions libs/lib-mongodb/src/db/db-index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './mongo.js';
export * from './errors.js';
71 changes: 71 additions & 0 deletions libs/lib-mongodb/src/db/errors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { DatabaseConnectionError, ErrorCode, ServiceError } from '@powersync/lib-services-framework';
import { isMongoServerError } from './mongo.js';
import { MongoNetworkError, MongoServerSelectionError } from 'mongodb';

export function mapConnectionError(err: any): ServiceError {
const cause = err.cause;
if (ServiceError.isServiceError(err)) {
return err;
} else if (isMongoServerError(err)) {
if (err.codeName == 'AuthenticationFailed') {
return new DatabaseConnectionError(
ErrorCode.PSYNC_S1306,
'MongoDB authentication failed. Check the username and password.',
err
);
} else if (err.codeName == 'Unauthorized') {
return new DatabaseConnectionError(
ErrorCode.PSYNC_S1307,
'MongoDB authorization issue. Check that the user has the required permissions.',
err
);
}
// Fallback
return new DatabaseConnectionError(ErrorCode.PSYNC_S1301, `MongoDB server error: ${err.codeName}`, err);
} else if (isNetworkError(cause)) {
if (hasCode(cause.cause, 'ERR_SSL_TLSV1_ALERT_INTERNAL_ERROR')) {
// This specifically happens on shared Atlas clusters where the IP Access List is not set up correctly.
// Since it's a shared cluster, the connection is not blocked completely, but closes during the TLS setup.
return new DatabaseConnectionError(
ErrorCode.PSYNC_S1303,
'Internal TLS Error. Check IP Access List on the cluster.',
err
);
} else if (hasCode(cause.cause, 'ENOTFOUND')) {
return new DatabaseConnectionError(
ErrorCode.PSYNC_S1304,
'DNS lookup error. Check that the hostname is correct.',
err
);
}
// Fallback
return new DatabaseConnectionError(ErrorCode.PSYNC_S1302, 'MongoDB network error', err);
} else if (err.code == 'ENOTFOUND') {
return new DatabaseConnectionError(
ErrorCode.PSYNC_S1304,
'DNS lookup error. Check that the hostname is correct.',
err
);
} else if (isMongoServerSelectionError(err) && err.message.includes('Server selection timed out')) {
return new DatabaseConnectionError(
ErrorCode.PSYNC_S1305,
'Connection timed out. Check the IP Access List on the cluster.',
err
);
} else {
// Fallback
return new DatabaseConnectionError(ErrorCode.PSYNC_S1301, 'MongoDB connection error', err);
}
}

function isNetworkError(err: any): err is MongoNetworkError {
return err?.name === 'MongoNetworkError';
}

function isMongoServerSelectionError(err: any): err is MongoServerSelectionError {
return err?.name === 'MongoServerSelectionError';
}

function hasCode(err: any, code: string): boolean {
return err?.code == code;
}
4 changes: 2 additions & 2 deletions libs/lib-mongodb/src/types/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { LookupOptions, makeHostnameLookupFunction } from '@powersync/lib-services-framework';
import { ErrorCode, LookupOptions, makeHostnameLookupFunction, ServiceError } from '@powersync/lib-services-framework';
import * as t from 'ts-codec';
import * as urijs from 'uri-js';

Expand Down Expand Up @@ -44,7 +44,7 @@ export function normalizeMongoConfig(options: BaseMongoConfigDecoded) {
const password = options.password ?? userInfo?.[1];

if (database == '') {
throw new Error(`database required`);
throw new ServiceError(ErrorCode.PSYNC_S1105, `MongoDB connection: database required`);
}

delete uri.userinfo;
Expand Down
2 changes: 1 addition & 1 deletion libs/lib-mongodb/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
"sourceMap": true
},
"include": ["src"],
"references": []
"references": [{ "path": "../lib-services" }]
}
24 changes: 15 additions & 9 deletions libs/lib-postgres/src/types/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { makeHostnameLookupFunction } from '@powersync/lib-services-framework';
import { ErrorCode, makeHostnameLookupFunction, ServiceError } from '@powersync/lib-services-framework';
import type * as jpgwire from '@powersync/service-jpgwire';
import * as service_types from '@powersync/service-types';
import * as t from 'ts-codec';
Expand Down Expand Up @@ -58,7 +58,10 @@ export function normalizeConnectionConfig(options: BasePostgresConnectionConfigD
if (options.uri) {
uri = urijs.parse(options.uri);
if (uri.scheme != 'postgresql' && uri.scheme != 'postgres') {
`Invalid URI - protocol must be postgresql, got ${uri.scheme}`;
throw new ServiceError(
ErrorCode.PSYNC_S1109,
`Invalid URI - protocol must be postgresql, got ${JSON.stringify(uri.scheme)}`
);
} else if (uri.scheme != 'postgresql') {
uri.scheme = 'postgresql';
}
Expand All @@ -80,23 +83,26 @@ export function normalizeConnectionConfig(options: BasePostgresConnectionConfigD
const cacert = options.cacert;

if (sslmode == 'verify-ca' && cacert == null) {
throw new Error('Explicit cacert is required for sslmode=verify-ca');
throw new ServiceError(
ErrorCode.PSYNC_S1104,
'Postgres connection: Explicit cacert is required for `sslmode: verify-ca`'
);
}

if (hostname == '') {
throw new Error(`hostname required`);
throw new ServiceError(ErrorCode.PSYNC_S1106, `Postgres connection: hostname required`);
}

if (username == '') {
throw new Error(`username required`);
throw new ServiceError(ErrorCode.PSYNC_S1107, `Postgres connection: username required`);
}

if (password == '') {
throw new Error(`password required`);
throw new ServiceError(ErrorCode.PSYNC_S1108, `Postgres connection: password required`);
}

if (database == '') {
throw new Error(`database required`);
throw new ServiceError(ErrorCode.PSYNC_S1105, `Postgres connection: database required`);
}

const lookupOptions = { reject_ip_ranges: options.reject_ip_ranges ?? [] };
Expand Down Expand Up @@ -132,8 +138,8 @@ export function validatePort(port: string | number): number {
if (typeof port == 'string') {
port = parseInt(port);
}
if (port < 1024) {
throw new Error(`Port ${port} not supported`);
if (port < 1024 || port > 65535) {
throw new ServiceError(ErrorCode.PSYNC_S1110, `Port ${port} not supported`);
}
return port;
}
Expand Down
4 changes: 2 additions & 2 deletions libs/lib-postgres/src/utils/pgwire_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import * as pgwire from '@powersync/service-jpgwire';

import { logger } from '@powersync/lib-services-framework';
import { logger, ServiceAssertionError } from '@powersync/lib-services-framework';

export function escapeIdentifier(identifier: string) {
return `"${identifier.replace(/"/g, '""').replace(/\./g, '"."')}"`;
Expand All @@ -24,7 +24,7 @@ export function autoParameter(arg: any): pgwire.StatementParam {
} else if (typeof arg == 'bigint') {
return { type: 'int8', value: arg };
} else {
throw new Error(`Unsupported query parameter: ${typeof arg}`);
throw new ServiceAssertionError(`Unsupported query parameter: ${typeof arg}`);
}
}

Expand Down
2 changes: 1 addition & 1 deletion libs/lib-postgres/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
"sourceMap": true
},
"include": ["src"],
"references": [{ "path": "../../packages/jpgwire" }, { "path": "../lib-services" }]
"references": [{ "path": "../lib-services" }, { "path": "../../packages/jpgwire" }]
}
1 change: 1 addition & 0 deletions libs/lib-services/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
},
"keywords": [],
"dependencies": {
"@powersync/service-errors": "workspace:*",
"ajv": "^8.12.0",
"better-ajv-errors": "^1.2.0",
"bson": "^6.8.0",
Expand Down
3 changes: 2 additions & 1 deletion libs/lib-services/src/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ErrorReporter } from './alerts/definitions.js';
import { NoOpReporter } from './alerts/no-op-reporter.js';
import { MigrationManager } from './migrations/MigrationManager.js';
import { ProbeModule, TerminationHandler, createFSProbe, createTerminationHandler } from './signals/signals-index.js';
import { ServiceAssertionError } from '@powersync/service-errors';

export enum ContainerImplementation {
REPORTER = 'reporter',
Expand Down Expand Up @@ -100,7 +101,7 @@ export class Container {
getImplementation<T>(identifier: ServiceIdentifier<T>): T {
const implementation = this.implementations.get(identifier);
if (!implementation) {
throw new Error(`Implementation for ${String(identifier)} has not been registered.`);
throw new ServiceAssertionError(`Implementation for ${String(identifier)} has not been registered.`);
}
return implementation;
}
Expand Down
3 changes: 1 addition & 2 deletions libs/lib-services/src/errors/errors-index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
export * from './framework-errors.js';
export * from './utils.js';
export * from '@powersync/service-errors';
150 changes: 0 additions & 150 deletions libs/lib-services/src/errors/framework-errors.ts

This file was deleted.

Loading
Loading