{"record":{"id":"71a9d4757f6a4f21","repo":"dotnet/orleans","slug":"custom-document-id-or-partition-key-providers-are","errorCode":null,"errorMessage":"Custom document id or partition key providers are not compatible with partition key path set to /GrainType","messagePattern":"Custom document id or partition key providers are not compatible with partition key path set to /GrainType","errorType":"exception","errorClass":"OrleansConfigurationException","httpStatus":null,"severity":"critical","filePath":"src/Azure/Orleans.Persistence.Cosmos/CosmosGrainStorage.cs","lineNumber":333,"sourceCode":"            foreach (var idx in _options.StateFieldsToIndex)\n            {\n                var path = idx.StartsWith(\"/\") ? idx[1..] : idx;\n                stateContainer.IndexingPolicy.IncludedPaths.Add(new IncludedPath { Path = $\"/\\\"State\\\"/\\\"{path}\\\"/?\" });\n            }\n        }\n\n        const int maxRetries = 3;\n        for (var retry = 0; retry <= maxRetries; ++retry)\n        {\n            var containerResponse = await db.CreateContainerIfNotExistsAsync(stateContainer, _options.ContainerThroughputProperties);\n\n            if (containerResponse.StatusCode == HttpStatusCode.OK || containerResponse.StatusCode == HttpStatusCode.Created)\n            {\n                var container = containerResponse.Resource;\n                _partitionKeyPath = container.PartitionKeyPath;\n                if (_partitionKeyPath == GRAINTYPE_PARTITION_KEY_PATH &&\n                    (_documentIdProvider is not DefaultDocumentIdProvider defaultProvider || defaultProvider.HasCustomPartitionKeyProvider))\n                    throw new OrleansConfigurationException(\"Custom document id or partition key providers are not compatible with partition key path set to /GrainType\");\n            }\n\n            if (retry == maxRetries || dbResponse.StatusCode != HttpStatusCode.Created || containerResponse.StatusCode == HttpStatusCode.Created)\n            {\n                break;  // Apparently some throttling logic returns HttpStatusCode.OK (not 429) when the collection wasn't created in a new DB.\n            }\n            await Task.Delay(1000);\n        }\n    }\n\n    private async Task TryDeleteDatabase()\n    {\n        try\n        {\n            await _client.GetDatabase(_options.DatabaseName).DeleteAsync().ConfigureAwait(false);\n        }\n        catch (CosmosException dce) when (dce.StatusCode == HttpStatusCode.NotFound)\n        {","sourceCodeStart":315,"sourceCodeEnd":351,"githubUrl":"https://github.com/dotnet/orleans/blob/fca799fa70ecb6ad975224271703ca43221f58de/src/Azure/Orleans.Persistence.Cosmos/CosmosGrainStorage.cs#L315-L351","documentation":"Thrown during Cosmos container initialization when the partition key path is /GrainType (GRAINTYPE_PARTITION_KEY_PATH) but a custom document ID or partition key provider is registered. The /GrainType partition strategy is an Orleans-managed scheme that expects the DefaultDocumentIdProvider without a custom partition key provider. Mixing the two is explicitly forbidden because it would produce inconsistent partition key assignments.","triggerScenarios":"Cosmos container was created or found with PartitionKeyPath=\"/GrainType\", and _documentIdProvider is not a DefaultDocumentIdProvider (or it is, but HasCustomPartitionKeyProvider is true — meaning an IPartitionKeyProvider was injected). This combination is detected during the Init lifecycle stage after CreateContainerIfNotExistsAsync.","commonSituations":"Developer configures UseCosmosGrainStorageWithGrainTypePartitionKeyPath (or sets the container partition key to /GrainType) but also calls ConfigurePartitionKeyProvider or AddPartitionKeyProvider to register a custom IPartitionKeyProvider. Mixing two partitioning strategies. Copy-paste config from one provider to another.","solutions":["Choose one partition strategy: either use /GrainType path (remove custom IPartitionKeyProvider/IDocumentIdProvider registrations) or use a custom provider (change the container partition key path to something else like /PartitionKey).","If you need custom partition keys, do not set the container's partition key path to /GrainType.","Remove the ConfigurePartitionKeyProvider call if using the /GrainType default strategy.","Delete and recreate the Cosmos container with the correct partition key path for the chosen strategy."],"exampleFix":"// before: conflicting configuration\nsiloBuilder.AddCosmosGrainStorage(\"store\", o =>\n{\n    // container has /GrainType partition key\n});\nsiloBuilder.Services.AddSingleton<IPartitionKeyProvider, MyPartitionKeyProvider>();\n\n// after: pick one strategy\nsiloBuilder.AddCosmosGrainStorage(\"store\", o =>\n{\n    o.PartitionKeyPath = \"/PartitionKey\"; // custom provider strategy\n});","handlingStrategy":"validation","validationCode":"// At startup, verify partition key path and provider strategy are compatible\nvar partitionKeyPath = configuration[\"Orleans:Persistence:store:PartitionKeyPath\"];\nvar hasCustomProvider = sp.GetService<IPartitionKeyProvider>() is not null\n    || sp.GetKeyedService<IDocumentIdProvider>(\"store\") is not DefaultDocumentIdProvider;\nif (partitionKeyPath == \"/GrainType\" && hasCustomProvider)\n    throw new InvalidOperationException(\"Cannot use /GrainType partition with a custom ID/partition provider.\");","typeGuard":null,"tryCatchPattern":"try { await host.StartAsync(ct); }\ncatch (OrleansConfigurationException ex) when (ex.Message.Contains(\"not compatible with partition key path\"))\n{\n    logger.LogCritical(ex, \"Cosmos partition key path /GrainType conflicts with custom provider — choose one strategy.\");\n    throw;\n}","preventionTips":["Choose one partition strategy upfront: /GrainType default OR custom IDocumentIdProvider/IPartitionKeyProvider.","Document the chosen partition strategy in the project's configuration docs.","Do not mix ConfigurePartitionKeyProvider with /GrainType container setup.","Delete and recreate the Cosmos container when switching partition strategies."],"tags":["cosmos-db","partition-key","configuration","document-id-provider","incompatible-config","orleans"],"backgroundTag":null,"analyzedSha":"fca799fa70ecb6ad975224271703ca43221f58de","analyzedAt":"2026-08-13T19:55:57.938Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}