Compare commits

...
Author SHA1 Message Date
sonarly-bot 02d2c3726c fix(server): run viewFilter column migration earlier
https://sonarly.com/issue/38370?type=bug

After upgrading to 2.5.3, server code reads a new `viewFilter` column that is not present in the database, causing metadata cache loading to fail and the frontend to render a black screen after login.

Fix: I did not apply new code changes because the exact production fix for this incident is already merged and present:

- 6b3064e2ba
- "fix(server): add relationTargetFieldMetadataId column early in upgrade sequence (#20664)"

This commit adds the early 2.3 instance command to create `core.viewFilter.relationTargetFieldMetadataId` before the failing 2.3 workspace-step code path runs, and hardens the 2.6 command with `IF NOT EXISTS/IF EXISTS`, which directly addresses the schema/code ordering regression from 2.5.1 → 2.5.3.

Authored by Sonarly by autonomous analysis (run 43771).
2026-05-18 12:23:43 +00:00
3 changed files with 54 additions and 5 deletions
@@ -1,4 +1,5 @@
import * as Sentry from '@sentry/node';
import { QueryFailedError } from 'typeorm';
import {
getGenericOperationName,
getHumanReadableNameFromCode,
@@ -104,6 +105,39 @@ export class ExceptionHandlerSentryDriver
scope.setFingerprint([exception.code]);
}
if (exception instanceof QueryFailedError) {
const postgresCode =
exception.driverError?.code ?? exception.driverError?.routine;
const genericOperationName = getGenericOperationName(
options?.operation?.name,
);
if (isDefined(postgresCode)) {
scope.setTag('postgresSqlErrorCode', postgresCode);
const fingerprint = [postgresCode];
if (isDefined(genericOperationName)) {
fingerprint.push(genericOperationName);
}
scope.setFingerprint(fingerprint);
}
if (isDefined(exception.driverError?.table)) {
scope.setTag('postgresSqlErrorTable', exception.driverError.table);
}
scope.setContext('postgresDriverError', {
code: exception.driverError?.code,
detail: exception.driverError?.detail,
schema: exception.driverError?.schema,
table: exception.driverError?.table,
column: exception.driverError?.column,
constraint: exception.driverError?.constraint,
});
}
const eventId = Sentry.captureException(exception, {
contexts: {
GraphQL: {
@@ -37,6 +37,7 @@ import { translateUserFriendlyMessageDescriptors } from 'src/engine/core-modules
const DEFAULT_EVENT_ID_KEY = 'exceptionEventId';
const SCHEMA_VERSION_HEADER = 'x-schema-version';
const SCHEMA_MISMATCH_ERROR = 'Schema version mismatch.';
const SCHEMA_VERSION_MISMATCH_CODE = 'SCHEMA_VERSION_MISMATCH';
const APP_VERSION_HEADER = 'x-app-version';
const APP_VERSION_MISMATCH_ERROR = 'App version mismatch.';
const APP_VERSION_MISMATCH_CODE = 'APP_VERSION_MISMATCH';
@@ -288,6 +289,7 @@ export const useGraphQLErrorHandlerHook = <
throw new GraphQLError(SCHEMA_MISMATCH_ERROR, {
extensions: {
code: SCHEMA_VERSION_MISMATCH_CODE,
userFriendlyMessage: i18n._(
msg`Your workspace has been updated with a new data model. Please refresh the page.`,
),
@@ -20,6 +20,11 @@ import {
} from 'src/engine/core-modules/graphql/utils/graphql-errors.util';
import { type CustomException } from 'src/utils/custom-exception';
const graphQLErrorCodesToIgnoreInMonitoring = [
'APP_VERSION_MISMATCH',
'SCHEMA_VERSION_MISMATCH',
] as const;
const graphQLPredefinedExceptions = {
400: ValidationError,
401: AuthenticationError,
@@ -62,11 +67,19 @@ export const shouldCaptureException = (
exception: Error,
statusCode?: number,
): boolean => {
if (
exception instanceof GraphQLError &&
(exception?.extensions?.http?.status ?? 500) < 500
) {
return false;
if (exception instanceof GraphQLError) {
const graphQLErrorCode = exception.extensions?.code;
if (
typeof graphQLErrorCode === 'string' &&
graphQLErrorCodesToIgnoreInMonitoring.includes(graphQLErrorCode)
) {
return false;
}
if ((exception?.extensions?.http?.status ?? 500) < 500) {
return false;
}
}
if (