doc/adr/0008-empty-string-as-default-tenant-id.md
Date: 2026-01-27
Accepted
The multitenancy system in Elsa supports an optional mode where, when multitenancy is disabled, the system assumes a single tenant. When enabled, there's still a default tenant involved. The convention has been to use null as the tenant ID for the default tenant.
However, this convention created several issues:
DefaultTenantResolverPipelineInvoker attempts to build a dictionary of tenants by their ID using ToDictionary(x => x.Id), which throws an exception because dictionaries do not support null keys.null, empty string (""), and string literal "default" interchangeably to refer to the default tenant across different parts of the system (e.g., in configuration files and database records).null as a sentinel value for "default" is implicit and can be unclear to developers reading the code.We will standardize on using an empty string ("") as the tenant ID for the default tenant instead of null. This decision includes:
Tenant.DefaultTenantId = "" to explicitly document the convention.Tenant.Default.Id from null! to use the DefaultTenantId constant.NormalizeTenantId() extension method that converts null to empty string, ensuring backwards compatibility with code that still uses null.DefaultTenantResolverPipelineInvokerTenantResolverContextDefaultTenantResolverPipelineInvoker.NormalizeTenantId() extension method ensures that existing code using null or empty string will work correctly.DefaultTenantId constant makes the convention clear and self-documenting.null tenant IDs will need to be normalized to empty strings, though the normalization helper provides a runtime solution.