microsoft/aspire · error · ArgumentException

Manifest field dictionaries must use string keys.

Error message

Manifest field dictionaries must use string keys.

What it means

Dictionaries passed as manifest field values must have string keys because JSON objects only support string keys. When an IDictionary entry's key is not a string (e.g. int, enum, or a custom key type), the normalizer throws this ArgumentException (note: without a parameter name).

Solutions

  1. Convert the dictionary to Dictionary<string, object?> with keys serialized via ToString() before passing
  2. Use StringEnumConverters or map enum keys to their string names explicitly
  3. For numeric keys, prefix/convert them to strings (e.g. key.ToString(CultureInfo.InvariantCulture))

Example fix

// before
var replicas = new Dictionary<WorkloadKind, int> { [WorkloadKind.Web] = 3 };
manifest.WithField("spec.replicasByKind", replicas);
// after
var replicas = new Dictionary<string, object?> { [WorkloadKind.Web.ToString()] = 3 };
manifest.WithField("spec.replicasByKind", replicas);
Defensive patterns

Strategy: validation

Validate before calling

bool allStringKeys = dict is IDictionary d && d.Keys.Cast<object>().All(k => k is string);

Type guard

static bool HasStringKeys(IDictionary d) => d.Keys.Cast<object>().All(k => k is string);

Try / catch

try { manifest.WithField(path, dict); } catch (ArgumentException ex) when (ex.Message.Contains("string keys")) { var fixedDict = dict.Keys.Cast<object>().ToDictionary(k => k.ToString()!, k => dict[k]); manifest.WithField(path, fixedDict); }

Prevention

When it happens

Trigger: Calling WithField with a Dictionary<int, ...>, Dictionary<MyEnum, ...>, Hashtable, or any IDictionary whose keys are not strings. Also occurs when passing a dictionary that got boxed into IDictionary with non-string keys at runtime.

Common situations: Using enums as lookup keys, building maps from parsed data with numeric keys, or passing a Hashtable copied from legacy code. Developers expect keys to be auto-stringified, but the library requires explicit strings.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16). Data as JSON: /api/errors/a865c14bb2beac8a. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Hosting.Kubernetes/KubernetesManifestResource.cs:243

            JsonValueKind.True => true,
            JsonValueKind.False => false,
            JsonValueKind.Number when element.TryGetInt64(out var longValue) => longValue,
            JsonValueKind.Number => element.GetDouble(),
            JsonValueKind.Array => element.EnumerateArray().Select(NormalizeJsonElement).ToList(),
            JsonValueKind.Object => element.EnumerateObject().ToDictionary(prop => prop.Name, prop => NormalizeJsonElement(prop.Value), StringComparer.Ordinal),
            _ => throw new ArgumentException($"Unsupported JSON value kind '{element.ValueKind}'.", nameof(element))
        };
    }

    private static Dictionary<string, object?> NormalizeDictionary(IDictionary dictionary)
    {
        var result = new Dictionary<string, object?>(StringComparer.Ordinal);

        foreach (DictionaryEntry entry in dictionary)
        {
            if (entry.Key is not string key)
            {
                throw new ArgumentException("Manifest field dictionaries must use string keys.");
            }

            result[key] = NormalizeManifestValue(entry.Value);
        }

        return result;
    }

    private static List<object?> NormalizeEnumerable(IEnumerable enumerable)
    {
        var result = new List<object?>();

        foreach (var item in enumerable)
        {
            result.Add(NormalizeManifestValue(item));
        }

        return result;

View on GitHub (pinned to 25830f84bd)