dotnet/orleans · error · ArgumentException

Provider type {providerType} must implement IDocumentIdProvi

Error message

Provider type {providerType} must implement IDocumentIdProvider or IPartitionKeyProvider.

What it means

Thrown by HostingExtensions when registering a provider type for document ID or partition key resolution, but the type implements neither IDocumentIdProvider nor IPartitionKeyProvider. The code checks IPartitionKeyProvider.IsAssignableFrom(providerType); if false, it throws ArgumentException naming both required interfaces.

Source

Thrown at src/Azure/Orleans.Persistence.Cosmos/HostingExtensions.cs:295

        if (typeof(IDocumentIdProvider).IsAssignableFrom(providerType))
        {
            services.AddKeyedSingleton(typeof(IDocumentIdProvider), name, providerType);
            return;
        }

#pragma warning disable CS0618 // Type or member is obsolete
        if (typeof(IPartitionKeyProvider).IsAssignableFrom(providerType))
        {
            services.AddKeyedSingleton(typeof(IPartitionKeyProvider), name, providerType);
            if (registerUnkeyedPartitionProvider)
            {
                services.TryAddSingleton(typeof(IPartitionKeyProvider), providerType);
            }

            return;
        }

        throw new ArgumentException(
            $"Provider type {providerType} must implement {nameof(IDocumentIdProvider)} or {nameof(IPartitionKeyProvider)}.",
            nameof(providerType));
#pragma warning restore CS0618 // Type or member is obsolete
    }
}

View on GitHub (pinned to fca799fa70)

Solutions

  1. Ensure the provider class implements IDocumentIdProvider (or the obsolete IPartitionKeyProvider), e.g., class MyProvider : IDocumentIdProvider { ... }.
  2. Verify the correct type is passed to the hosting extension — not the grain type, not the options type.
  3. Check that the Orleans.Persistence.Cosmos package is referenced so the interface is available.
  4. If migrating from IPartitionKeyProvider (obsolete), switch to IDocumentIdProvider.

Example fix

// before: missing interface
public class MyPartitionKeyProvider
{
    public string GetPartitionKey(GrainId grainId) => grainId.ToString();
}

// after: implement the interface
public class MyPartitionKeyProvider : IDocumentIdProvider
{
    public DocumentId GetDocumentId(GrainId grainId) => new(grainId.ToString(), grainId.ToString());
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Verify before registration
var providerType = typeof(MyProvider);
if (!typeof(IDocumentIdProvider).IsAssignableFrom(providerType)
    && !typeof(IPartitionKeyProvider).IsAssignableFrom(providerType))
    throw new InvalidOperationException($"{providerType.Name} must implement IDocumentIdProvider or IPartitionKeyProvider.");

Type guard

static bool IsValidProviderType(Type t) =>
    typeof(IDocumentIdProvider).IsAssignableFrom(t) || typeof(IPartitionKeyProvider).IsAssignableFrom(t);

Try / catch

try { siloBuilder.AddPartitionKeyProvider(name, providerType); }
catch (ArgumentException ex) when (ex.Message.Contains("must implement"))
{
    logger.LogError(ex, "Provider type does not implement IDocumentIdProvider or IPartitionKeyProvider.");
    throw;
}

Prevention

When it happens

Trigger: Calling a hosting extension (e.g., AddPartitionKeyProvider or AddDocumentIdProvider) with a Type that does not implement either required interface. The extension checks assignability before registering and throws if neither interface is satisfied.

Common situations: Developer creates a class intended to be a partition key provider but forgets to implement IPartitionKeyProvider or IDocumentIdProvider. Renaming an interface during a refactor. Passing the wrong type by mistake (e.g., the grain class instead of the provider class). Version mismatch where the interface moved to a different namespace.

Related errors


AI-assisted analysis of dotnet/orleans@fca799fa70 (2026-08-13). Data as JSON: /api/errors/7f4ce6a94773f232. Report an issue: GitHub.