dotnet/orleans · error · ArgumentException

Azure Table partition keys must not contain '/', '\\', '#',

Error message

Azure Table partition keys must not contain '/', '\\', '#', '?', or control characters.

What it means

Thrown by ValidatePartitionKey when the computed partition key contains a character disallowed by Azure Tables: '/', '\\', '#', '?', or any control character (U+0000-U+001F or U+007F-U+009F). This guards custom mappers that may not escape such characters.

Source

Thrown at src/Azure/Orleans.Journaling.AzureStorage/AzureTableJournalStorageOptions.cs:165

        }
    }

    private static void ValidatePartitionKey(string partitionKey, string parameterName)
    {
        if (partitionKey.Length > 1024)
        {
            throw new ArgumentException(
                "Azure Table partition keys must not exceed 1,024 characters.",
                parameterName);
        }

        foreach (var character in partitionKey)
        {
            if (character is '/' or '\\' or '#' or '?'
                or >= '\u0000' and <= '\u001F'
                or >= '\u007F' and <= '\u009F')
            {
                throw new ArgumentException(
                    "Azure Table partition keys must not contain '/', '\\', '#', '?', or control characters.",
                    parameterName);
            }
        }
    }

    private static bool IsAsciiLetter(char character)
        => character is >= 'A' and <= 'Z' or >= 'a' and <= 'z';

    /// <summary>
    /// Configures the <see cref="TableServiceClient"/> using a connection string.
    /// </summary>
    public void ConfigureTableServiceClient(string connectionString)
    {
        ArgumentException.ThrowIfNullOrWhiteSpace(connectionString);
        CreateClient = ct => Task.FromResult(new TableServiceClient(connectionString, ClientOptions));
    }

View on GitHub (pinned to fca799fa70)

Solutions

  1. In your custom mapper, escape disallowed characters (Uri.EscapeDataString or a targeted replace) before returning.
  2. Prefer reusing GetDefaultPartitionKey inside your custom mapper for the escaping step.
  3. Strip or replace '/', '\', '#', '?' and control chars at the source of the id.

Example fix

// before
options.GetPartitionKey = id => id.Value; // raw, may contain '/'
// after
options.GetPartitionKey = id => Uri.EscapeDataString(id.Value);
Defensive patterns

Strategy: validation

Validate before calling

static bool IsValidPartitionKey(string k) =>
    k.Length <= 1024 && !k.Any(c => c is '/' or '\\' or '#' or '?' || c <= '\u001F' || c >= '\u007F' && c <= '\u009F');

Type guard

static bool IsPartitionKeySafe(string k) => !k.Any(c => c is '/' or '\\' or '#' or '?' || c <= '\u001F' || c >= '\u007F' && c <= '\u009F');

Prevention

When it happens

Trigger: A custom GetPartitionKey mapper returns a raw string containing '/', '\', '#', '?', or a control character; the default mapper percent-encodes these so this normally only fires for user-supplied mappers.

Common situations: A custom mapper concatenates a path-like id with '/' separators; a mapper returns a JournalId.Value verbatim that contains a '#'; binary/control data leaks into the key.

Related errors


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