{"record":{"id":"444844246521d040","repo":"elsa-workflows/elsa-core","slug":"a-conversation-user-id-is-required-parameter-conversation-444844","errorCode":null,"errorMessage":"A conversation user ID is required. (Parameter 'conversation')","messagePattern":"A conversation user ID is required\\. \\(Parameter 'conversation'\\)","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/modules/Elsa.AI.Persistence.EFCore/Stores/EFCoreAIConversationStore.cs","lineNumber":234,"sourceCode":"\n    private static bool BelongsToTenant(string? storedTenantId, string? requestedTenantId) =>\n        string.Equals(NormalizeTenantId(storedTenantId), NormalizeTenantId(requestedTenantId), StringComparison.Ordinal);\n\n    private static string NormalizeTenantId(string? tenantId) => tenantId ?? \"\";\n\n    private static void ValidateUserOwnership(AIConversationRecord record, AIConversation conversation)\n    {\n        if (!string.IsNullOrWhiteSpace(record.UserId) && !string.Equals(record.UserId, conversation.UserId, StringComparison.Ordinal))\n            throw new InvalidOperationException(\"Cannot overwrite an AI conversation that belongs to another user.\");\n    }\n\n    private static void Validate(AIConversation conversation)\n    {\n        if (string.IsNullOrWhiteSpace(conversation.Id))\n            throw new ArgumentException(\"A conversation ID is required.\", nameof(conversation));\n\n        if (string.IsNullOrWhiteSpace(conversation.UserId))\n            throw new ArgumentException(\"A conversation user ID is required.\", nameof(conversation));\n    }\n}\n","sourceCodeStart":216,"sourceCodeEnd":237,"githubUrl":"https://github.com/elsa-workflows/elsa-core/blob/fe9217bdfa0e27f0e09e45006eb6898f616e513d/src/modules/Elsa.AI.Persistence.EFCore/Stores/EFCoreAIConversationStore.cs#L216-L237","documentation":"The store's Validate method requires a non-whitespace UserId on every AIConversation being saved. UserId is used for ownership checks (ValidateUserOwnership) and must be present to attribute the conversation; otherwise ArgumentException with paramName 'conversation' is thrown.","triggerScenarios":"Calling SaveAsync with an AIConversation whose UserId is null, empty, or whitespace (Id validation passed but user ID validation failed).","commonSituations":"Service-to-service calls without a user context; authentication not resolving the current user's identifier; a mapper that copies Id but not UserId; creating conversations from background jobs with no ambient user.","solutions":["Populate conversation.UserId with the authenticated user's identifier before SaveAsync.","If truly system-initiated, use an explicit system user identifier rather than null/empty (note ValidateUserOwnership only guards overwrites of records that already have a UserId).","Add a pre-save check in your service layer that rejects conversations without a user."],"exampleFix":"// before\nawait store.SaveAsync(new AIConversation { Id = id });\n// after\nawait store.SaveAsync(new AIConversation { Id = id, UserId = currentUser.Id ?? \"system\" });","handlingStrategy":"validation","validationCode":"if (string.IsNullOrWhiteSpace(conversation.UserId)) throw new ArgumentException(\"A conversation user ID is required before SaveAsync.\");","typeGuard":"static bool HasUser(AIConversation c) => !string.IsNullOrWhiteSpace(c.UserId);","tryCatchPattern":"try { await store.SaveAsync(conversation); }\ncatch (ArgumentException ex) when (ex.ParamName == \"conversation\" && ex.Message.Contains(\"user ID\")) { /* resolve current user or use a system identity */ }","preventionTips":["Resolve the user identity from auth context before creating conversations.","Use an explicit system user for background/service-initiated conversations.","Validate at the service boundary, not only at the store.","Keep UserId assignment next to Id assignment in one factory method."],"tags":["ef-core","ai-conversations","validation","argument"],"backgroundTag":"missing-required-argument","analyzedSha":"fe9217bdfa0e27f0e09e45006eb6898f616e513d","analyzedAt":"2026-09-13T20:32:34.702Z","contentChangedAt":"2026-09-13T20:32:34.702Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}