dotnet/orleans · error · ArgumentException
Journal metadata property names must not contain null charac
Error message
Journal metadata property names must not contain null characters.
What it means
Thrown by AzureBlobJournalStorage when validating a caller-supplied metadata property name passed to Append/Replace/SetMetadata. The journal reserves certain metadata keys for its own bookkeeping (format, checkpoint, checkpoint_offset, wal_generation, and anything starting with '$'), and embedded NUL characters corrupt the Azure Blob metadata layer, so both are rejected up front before any write reaches the service.
Source
Thrown at src/Azure/Orleans.Journaling.AzureStorage/AzureBlobJournalStorage.cs:1019
changed = true;
}
}
return changed;
}
private static void ValidateCallerMetadataProperty(string key, string value)
{
ValidateCallerMetadataPropertyName(key);
ArgumentNullException.ThrowIfNull(value);
}
private static void ValidateCallerMetadataPropertyName(string key)
{
ArgumentException.ThrowIfNullOrWhiteSpace(key);
if (key.IndexOf('\0') >= 0)
{
throw new ArgumentException("Journal metadata property names must not contain null characters.", nameof(key));
}
if (IsProviderMetadataKey(key))
{
throw new ArgumentException($"Journal metadata property '{key}' is provider-owned.", nameof(key));
}
}
private static bool IsProviderMetadataKey(string key)
=> string.Equals(key, FormatMetadataKey, StringComparison.OrdinalIgnoreCase)
|| string.Equals(key, CheckpointMetadataKey, StringComparison.OrdinalIgnoreCase)
|| string.Equals(key, CheckpointOffsetMetadataKey, StringComparison.OrdinalIgnoreCase)
|| string.Equals(key, WalGenerationMetadataKey, StringComparison.OrdinalIgnoreCase)
|| key.StartsWith("$", StringComparison.Ordinal);
private static ETag ToAzureETag(string eTag)
{
ArgumentException.ThrowIfNullOrWhiteSpace(eTag);View on GitHub (pinned to fca799fa70)
Solutions
- Sanitize all caller metadata keys before passing them: strip NUL characters or reject them, e.g. key.Replace("\0", string.Empty).
- Restrict metadata keys to printable ASCII or UTF-8 identifiers without control characters.
- If you need binary metadata, put it in the metadata VALUE, not the key, or store it in the journal payload itself.
Example fix
// before
var meta = new Dictionary<string, string> { ["user\0id"] = "abc" };
await storage.AppendAsync(data, meta, ct);
// after
var meta = new Dictionary<string, string> { ["user_id"] = "abc" };
await storage.AppendAsync(data, meta, ct); Defensive patterns
Strategy: validation
Validate before calling
static bool IsValidMetadataKey(string key)
=> !string.IsNullOrWhiteSpace(key)
&& key.IndexOf('\0') < 0
&& !key.StartsWith("$", StringComparison.Ordinal)
&& !IsReservedKey(key);
static bool IsReservedKey(string key)
=> key.Equals("format", StringComparison.OrdinalIgnoreCase)
|| key.Equals("checkpoint", StringComparison.OrdinalIgnoreCase)
|| key.Equals("checkpoint_offset", StringComparison.OrdinalIgnoreCase)
|| key.Equals("wal_generation", StringComparison.OrdinalIgnoreCase); Prevention
- Sanitize metadata keys from untrusted sources before passing them to journal storage APIs.
- Namespace application metadata keys (e.g. 'app.foo') to avoid collisions with reserved keys.
- Add a unit test that asserts reserved keys are rejected.
When it happens
Trigger: Calling an IJournalStorage method that accepts IReadOnlyDictionary<string,string> metadata (e.g. AppendAsync, ReplaceAsync, CreateIfNotExistsAsync with metadata) and passing a dictionary whose key contains a '\0' character. Validation runs synchronously in ValidateCallerMetadataPropertyName before the first network call.
Common situations: Serializing a binary key or a struct value into a metadata key name; copying keys from an untrusted source without sanitization; using a key derived from a GUID or byte array that was not first encoded as a clean string.
Related errors
- Journal metadata property '{key}' is provider-owned.
- MaxMetadataOnlyConflictRetries must be non-negative.
- MetadataOnlyConflictInitialBackoff must be non-negative.
- MetadataOnlyConflictMaxBackoff must be non-negative.
- The journal id must not be the default value.
AI-assisted analysis of dotnet/orleans@fca799fa70 (2026-08-13).
Data as JSON: /api/errors/b80072df61b48096.
Report an issue: GitHub.