dotnet/orleans · error · InvalidOperationException

Inform grain id in format

Error message

Inform grain id in format {id},{additionalKey}

What it means

InvalidOperationException from GrainStateHelper.GetGrainId when the implementation type implements IGrainWithIntegerCompoundKey but the id does not split into exactly two comma-separated parts. Requires exactly 'integer,additionalKey'. Note the message text differs slightly from error 355 (no stray backticks) but the contract is identical for integer compound keys.

Solutions

  1. Pass ids for integer-compound grains as 'long,additionalKey' with exactly one comma.
  2. Validate format and that the first part is a 64-bit integer before calling.
  3. Confirm the grain interface marker type matches the key shape you expect.

Example fix

// before
var (gid, ext) = GrainStateHelper.GetGrainId(rawId, typeof(MyIntCompoundGrain));

// after
var parts = rawId.Split(',');
if (parts.Length != 2 || !long.TryParse(parts[0], out _))
    return BadRequest("id must be 'long,additionalKey'");
var (gid, ext) = GrainStateHelper.GetGrainId(rawId, typeof(MyIntCompoundGrain));
Defensive patterns

Strategy: validation

Validate before calling

var parts = id.Split(',');
if (parts.Length != 2 || !long.TryParse(parts[0], out _))
    return BadRequest("id must be 'long,additionalKey'");
var (gid, ext) = GrainStateHelper.GetGrainId(id, type);

Type guard

static bool IsValidIntCompoundId(string id) =>
    id.Split(',') is { Length: 2 } p && long.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 integer id malformed"); }

Prevention

When it happens

Trigger: Dashboard requests grain state for a grain whose implementation type is IGrainWithIntegerCompoundKey, and the id string does not contain exactly one comma (splitedGrainId.Length != 2). Convert.ToInt64 on a non-numeric first part would also throw and be wrapped by error 357.

Common situations: Malformed id from the dashboard UI, a grain registered with an integer compound key but invoked with only the long portion, or frontend code that omits the additional key.

Related errors


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

Appendix: source

Thrown at src/Dashboard/Orleans.Dashboard/Implementation/Helpers/GrainStateHelper.cs:30

    {
        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)))
            {
                grainId = Guid.Parse(id);
            }
            else if (implementationType.IsAssignableTo(typeof(IGrainWithStringKey)))
            {
                grainId = id;
            }
        }
        catch (Exception ex)

View on GitHub (pinned to fca799fa70)