dotnet/orleans · error · InvalidOperationException
Inform grain id in format `{ id},{additionalKey}`
Error message
Inform grain id in format `{ id},{additionalKey}` What it means
InvalidOperationException from GrainStateHelper.GetGrainId when the grain's implementation type implements IGrainWithGuidCompoundKey but the supplied id string does not split into exactly two comma-separated parts. The compound-guid format requires exactly 'guid,additionalKey' (the message has a stray backtick/braces typo but means the same format).
Source
Thrown at src/Dashboard/Orleans.Dashboard/Implementation/Helpers/GrainStateHelper.cs:22
using System.Linq;
using System.Reflection;
namespace Orleans.Dashboard.Implementation.Helpers;
internal static class GrainStateHelper
{
public static (object?, string) GetGrainId(string id, Type implementationType)
{
object? grainId = null;
string keyExtension = "";
var splitedGrainId = id.Split(",");
try
{
if (implementationType.IsAssignableTo(typeof(IGrainWithGuidCompoundKey)))
{
if (splitedGrainId.Length != 2)
throw new InvalidOperationException("Inform grain id in format `{ id},{additionalKey}`");
grainId = Guid.Parse(splitedGrainId.First());
keyExtension = splitedGrainId.Last();
}
else if (implementationType.IsAssignableTo(typeof(IGrainWithIntegerCompoundKey)))
{
if (splitedGrainId.Length != 2)
throw new InvalidOperationException("Inform grain id in format {id},{additionalKey}");
grainId = Convert.ToInt64(splitedGrainId.First());
keyExtension = splitedGrainId.Last();
}
else if (implementationType.IsAssignableTo(typeof(IGrainWithIntegerKey)))
{
grainId = Convert.ToInt64(id);
}
else if (implementationType.IsAssignableTo(typeof(IGrainWithGuidKey)))
{View on GitHub (pinned to fca799fa70)
Solutions
- Ensure ids for compound-key grains are passed as 'guid,additionalKey' with exactly one comma.
- Validate the format on the client/frontend before requesting grain state.
- If using single-key grains, make sure the grain interface marker matches (IGrainWithGuidKey vs IGrainWithGuidCompoundKey).
Example fix
// before
var (gid, ext) = GrainStateHelper.GetGrainId(rawId, typeof(MyCompoundGrain));
// rawId = "abc" -> throws
// after
var parts = rawId.Split(',');
if (parts.Length != 2 || !Guid.TryParse(parts[0], out _))
return BadRequest("id must be 'guid,additionalKey'");
var (gid, ext) = GrainStateHelper.GetGrainId(rawId, typeof(MyCompoundGrain)); Defensive patterns
Strategy: validation
Validate before calling
var parts = id.Split(',');
if (parts.Length != 2 || !Guid.TryParse(parts[0], out _))
return BadRequest("id must be 'guid,additionalKey'");
var (gid, ext) = GrainStateHelper.GetGrainId(id, type); Type guard
static bool IsValidGuidCompoundId(string id) =>
id.Split(',') is { Length: 2 } p && Guid.TryParse(p[0], out _); Try / catch
try { var (gid, ext) = GrainStateHelper.GetGrainId(id, type); }
catch (InvalidOperationException ex) when (ex.Message.Contains("grain id in format"))
{ return BadRequest("compound guid id malformed"); } Prevention
- Validate the 'guid,key' format on the client/frontend
- Match grain interface markers to the key shape
- Never pass a single-segment id to a compound-key grain
When it happens
Trigger: Dashboard invokes GetGrainId(id, implementationType) where implementationType is IGrainWithGuidCompoundKey and id does not contain exactly one comma (splitedGrainId.Length != 2). E.g. id='abc' or id='g1,g2,g3'.
Common situations: Dashboard grain-state inspection receives a malformed id from the frontend, a grain registered with a compound key invoked through a path that passes the raw key without the extension, or a client serializing only the primary key. The downstream Guid.Parse can also throw (wrapped by error 357).
Related errors
- Inform grain id in format {id},{additionalKey}
- Error when trying to convert grain Id
- The frontend cant support more than 6 silos
- Unknown Playground:Storage:Provider value '{storageProvider}
- count
AI-assisted analysis of dotnet/orleans@fca799fa70 (2026-08-13).
Data as JSON: /api/errors/c7ee6da523374aa2.
Report an issue: GitHub.