{"record":{"id":"de8ddb4a87e5425f","repo":"dotnet/orleans","slug":"journal-metadata-property-names-must-not-contain-n-de8ddb","errorCode":null,"errorMessage":"Journal metadata property names must not contain null characters.","messagePattern":"Journal metadata property names must not contain null characters\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Azure/Orleans.Journaling.AzureStorage/AzureTableJournalStorage.cs","lineNumber":1172,"sourceCode":"                changed = true;\n            }\n        }\n\n        return changed;\n    }\n\n    private static void ValidateCallerMetadataProperty(string key, string value)\n    {\n        ValidateCallerMetadataPropertyName(key);\n        ArgumentNullException.ThrowIfNull(value);\n    }\n\n    private static void ValidateCallerMetadataPropertyName(string key)\n    {\n        ArgumentException.ThrowIfNullOrWhiteSpace(key);\n        if (key.IndexOf('\\0') >= 0)\n        {\n            throw new ArgumentException(\"Journal metadata property names must not contain null characters.\", nameof(key));\n        }\n\n        if (key.StartsWith(\"$\", StringComparison.Ordinal))\n        {\n            throw new ArgumentException($\"Journal metadata property '{key}' is provider-owned.\", nameof(key));\n        }\n    }\n\n    private static ETag ToAzureETag(string eTag)\n    {\n        ArgumentException.ThrowIfNullOrWhiteSpace(eTag);\n        return new ETag(eTag);\n    }\n\n    private static bool IsEntityAlreadyExists(RequestFailedException exception)\n        => exception.Status == 409\n            && (string.Equals(exception.ErrorCode, \"EntityAlreadyExists\", StringComparison.Ordinal)\n                || exception.Message.Contains(\"already exists\", StringComparison.OrdinalIgnoreCase));","sourceCodeStart":1154,"sourceCodeEnd":1190,"githubUrl":"https://github.com/dotnet/orleans/blob/fca799fa70ecb6ad975224271703ca43221f58de/src/Azure/Orleans.Journaling.AzureStorage/AzureTableJournalStorage.cs#L1154-L1190","documentation":"A caller-supplied journal metadata property name contains a NUL (\\0) character. ValidateCallerMetadataPropertyName (AzureTableJournalStorage.cs:1167) rejects embedded NULs because they break string handling in Azure Table property names and downstream serialization. The argument blamed is `key`.","triggerScenarios":"Calling a metadata set/update API with a dictionary key or remove-set entry containing '\\0'; thrown at AzureTableJournalStorage.cs:1172.","commonSituations":"A key was read from a binary/encoded source without sanitizing; concatenated buffers introduced a NUL; user input was not validated before becoming a metadata key.","solutions":["Sanitize keys before the call: strip or reject NUL characters.","Validate keys come from a controlled vocabulary rather than raw external input.","Add a unit test asserting metadata keys are printable."],"exampleFix":"// before\nstorage.SetMetadata(new() { [badKey] = \"v\" }); // badKey contains '\\0'\n\n// after\nvar safeKey = badKey.Replace(\"\\0\", string.Empty);\nif (string.IsNullOrWhiteSpace(safeKey)) throw new ArgumentException(\"Empty key\");\nstorage.SetMetadata(new() { [safeKey] = \"v\" });","handlingStrategy":"validation","validationCode":"foreach (var k in metadata.Keys)\n    if (k.IndexOf('\\0') >= 0) throw new ArgumentException($\"Key '{k}' contains a NUL character\");","typeGuard":"static bool HasNoNul(string key) => key.IndexOf('\\0') < 0;","tryCatchPattern":null,"preventionTips":["Sanitize keys derived from binary or external input.","Reject non-printable key characters before the call.","Keep metadata keys from a controlled vocabulary."],"tags":["metadata","validation","api-usage"],"backgroundTag":null,"analyzedSha":"fca799fa70ecb6ad975224271703ca43221f58de","analyzedAt":"2026-08-13T19:55:57.938Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}