fix(server): log inner errors of WorkspaceMigrationRunnerException in workspace iterator (#19823)

## Summary

When a workspace migration action fails during workspace iteration (e.g.
during upgrade commands), only the wrapper message was logged:

```
[WorkspaceIteratorService] Error in workspace 7914ba64-...: Migration action 'create' for 'pageLayoutWidget' failed
```

The underlying error (transpilation/metadata/workspace schema) and its
stack were swallowed, making production debugging painful.

This PR adds a follow-up log entry for each inner error attached to a
`WorkspaceMigrationRunnerException`, including its message and stack
trace. The runner exception itself is untouched — it already exposes
structured `errors` (`actionTranspilation`, `metadata`,
`workspaceSchema`).

After this change, logs look like:

```
[WorkspaceIteratorService] Error in workspace 7914ba64-...: Migration action 'create' for 'pageLayoutWidget' failed
[WorkspaceIteratorService] Caused by actionTranspilation in workspace 7914ba64-...: <real reason>
    at ...
```

## Test plan

- [ ] Trigger a failing workspace migration (e.g. backfill record page
layouts) on a workspace and confirm the underlying cause + stack now
appear in logs.

Made with [Cursor](https://cursor.com)
This commit is contained in:
Charles Bochet 2026-04-17 22:31:35 +02:00 committed by GitHub
parent 3eeaebb0cc
commit fb5a1988b1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -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;
}