Compare commits

...
Author SHA1 Message Date
Sonarly Claude Code d87260536d chore: improve monitoring for fix: use unique name when creating workflow AI age
**Monitoring improvement:** Enhanced `WorkspaceMigrationBuilderException` to include validation error details in the exception message. Previously, Sentry only showed the generic caller-provided message (e.g., "Multiple validation errors occurred while creating agent"). Now the message includes the specific validation error codes and messages (e.g., "Multiple validation errors occurred while creating agent: [AGENT_ALREADY_EXISTS] Agent with name 'workflowAgentc719' already exists").

This is achieved by extracting error details from the structured `OrchestratorFailureReport` and appending them to the `super()` message. The change is safe because:
- All 55 callers use `instanceof WorkspaceMigrationBuilderException` for control flow, not string matching
- The structured `failedWorkspaceMigrationBuildResult` field remains unchanged
- The GraphQL error formatter at `workspace-migration-builder-exception-formatter.ts` already uses `error.message` (line 36), so the richer message will flow through to both Sentry and GraphQL error responses
2026-03-26 09:59:08 +00:00
Sonarly Claude Code 2e00457432 fix: use unique name when creating workflow AI agent step
https://sonarly.com/issue/18628?type=bug

Creating an AI_AGENT workflow step fails with a validation error when the workspace already has an agent with a colliding auto-generated name, blocking users from adding multiple AI agent steps to a workflow.

Fix: **Bug fix:** Added explicit unique `name` field (`'workflow-agent-' + v4()`) to both AI_AGENT step creation paths in `workflow-version-step-operations.workspace-service.ts`:

1. **New step creation** (line 443): When creating an AI_AGENT workflow step, the code previously relied on auto-generating the name from the label `'Workflow Agent' + workflowId.substring(0, 4)`. Since the label is deterministic per workflow, creating a second AI_AGENT step in the same workflow (or any workflow sharing the first 4 ID characters) would fail the agent name uniqueness validation. Now passes `name: 'workflow-agent-' + v4()` to guarantee uniqueness — matching the pattern used in the original code before the `AgentService` refactoring in commit 21c51ec251.

2. **Clone path** (line 712): The step duplication/clone path had the same issue — cloning an AI_AGENT step would try to create a new agent with the same auto-derived name as the original, failing the uniqueness check. Now also passes a unique `name`.

3. **Label fix**: Also added a missing space in the label: `'Workflow Agent'` + ID → `'Workflow Agent '` + ID (cosmetic, matches the intended display format).
2026-03-26 09:59:08 +00:00
2 changed files with 28 additions and 2 deletions
@@ -1,3 +1,5 @@
import { type AllMetadataName } from 'twenty-shared/metadata';
import { type WorkspaceMigrationOrchestratorFailedResult } from 'src/engine/workspace-manager/workspace-migration/types/workspace-migration-orchestrator.type';
export class WorkspaceMigrationBuilderException extends Error {
@@ -5,7 +7,29 @@ export class WorkspaceMigrationBuilderException extends Error {
public readonly failedWorkspaceMigrationBuildResult: WorkspaceMigrationOrchestratorFailedResult,
message = 'Workspace migration builder failed',
) {
super(message);
super(
`${message}: ${WorkspaceMigrationBuilderException.extractErrorDetails(failedWorkspaceMigrationBuildResult)}`,
);
this.name = 'WorkspaceMigrationBuilderException';
}
private static extractErrorDetails(
result: WorkspaceMigrationOrchestratorFailedResult,
): string {
const errorMessages: string[] = [];
for (const metadataName of Object.keys(result.report) as AllMetadataName[]) {
const validations = result.report[metadataName];
for (const validation of validations) {
for (const error of validation.errors) {
errorMessages.push(`[${error.code}] ${error.message}`);
}
}
}
return errorMessages.length > 0
? errorMessages.join(', ')
: 'unknown validation error';
}
}
@@ -440,8 +440,9 @@ export class WorkflowVersionStepOperationsWorkspaceService {
const newAgent = await this.agentService.createOneAgent(
{
name: 'workflow-agent-' + v4(),
label:
'Workflow Agent' + workflowVersion.workflowId.substring(0, 4),
'Workflow Agent ' + workflowVersion.workflowId.substring(0, 4),
icon: 'IconRobot',
description: '',
prompt:
@@ -709,6 +710,7 @@ export class WorkflowVersionStepOperationsWorkspaceService {
const clonedAgent = await this.agentService.createOneAgent(
{
name: 'workflow-agent-' + v4(),
label: existingAgent.label,
icon: existingAgent.icon ?? undefined,
description: existingAgent.description ?? undefined,