Compare commits

...
Author SHA1 Message Date
Charles Bochet 0a4f060423 refactor(server): use isDefined helper in workspace iterator inner-error logging
Made-with: Cursor
2026-04-17 22:20:48 +02:00
Charles Bochet 03dd3828f2 fix(server): handle non-Error inner causes defensively in workspace iterator
The runner exception's `errors` field is typed as `Error` but at runtime the
rejection reasons from `Promise.allSettled` can be any value. Fall back to
`String(innerError)` (and skip the stack arg) when the cause is not an Error
so we don't print `undefined` and lose the real cause.

Made-with: Cursor
2026-04-17 22:19:14 +02:00
Charles Bochet f1fd003c2e chore(server): drop workspace-iterator inner-error logging test
Made-with: Cursor
2026-04-17 22:18:35 +02:00
Charles Bochet c30984ac98 test(server): cover inner-error logging in WorkspaceIteratorService
Made-with: Cursor
2026-04-17 22:17:40 +02:00
Charles Bochet a21cf4fe1a fix(server): log inner errors of WorkspaceMigrationRunnerException in workspace iterator
When a workspace migration action fails during workspace iteration (e.g. during
upgrade commands), only the wrapper message was logged (e.g. "Migration action
'create' for 'pageLayoutWidget' failed"), hiding the actual underlying error
message and stack trace.

Also log each inner error (actionTranspilation, metadata, workspaceSchema)
with its own message and stack so production logs surface the real cause.

Made-with: Cursor
2026-04-17 22:13:45 +02:00
@@ -4,12 +4,14 @@ import { InjectRepository } from '@nestjs/typeorm';
import chalk from 'chalk';
import { isNonEmptyString } from '@sniptt/guards';
import { WorkspaceActivationStatus } from 'twenty-shared/workspace';
import { isDefined } from 'twenty-shared/utils';
import { In, MoreThanOrEqual, Repository } from 'typeorm';
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
import { GlobalWorkspaceDataSource } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-datasource';
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
import { buildSystemAuthContext } from 'src/engine/twenty-orm/utils/build-system-auth-context.util';
import { WorkspaceMigrationRunnerException } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/exceptions/workspace-migration-runner.exception';
export type WorkspaceIteratorArgs = {
workspaceIds?: string[];
@@ -104,12 +106,29 @@ export class WorkspaceIteratorService {
}
}
report.fail.forEach(({ error, workspaceId }) =>
report.fail.forEach(({ error, workspaceId }) => {
this.logger.error(
`Error in workspace ${workspaceId}: ${error.message}`,
error.stack,
),
);
);
if (error instanceof WorkspaceMigrationRunnerException && error.errors) {
for (const [label, innerError] of Object.entries(error.errors)) {
if (!isDefined(innerError)) continue;
if (innerError instanceof Error) {
this.logger.error(
`Caused by ${label} in workspace ${workspaceId}: ${innerError.message}`,
innerError.stack,
);
} else {
this.logger.error(
`Caused by ${label} in workspace ${workspaceId}: ${String(innerError)}`,
);
}
}
}
});
return report;
}