microsoft/aspire · error · JsonException

Expected a string token for Kubernetes MicroTime but found

Error message

Expected a string token for Kubernetes MicroTime but found {reader.TokenType}.

What it means

Thrown by KubernetesMicroTimeJsonConverter.Read when deserializing a Kubernetes MicroTime JSON value that is not a JSON string. The converter expects the token to be JsonTokenType.String so it can parse RFC3339 timestamps; any other token (number, null handled earlier, object) raises a JsonException.

Solutions

  1. Fix the producing side to emit RFC3339 strings (e.g. "2024-01-01T12:00:00.123456Z") instead of numeric epochs.
  2. If you control deserialization, pre-parse with a JsonDocument check and convert numeric values to ISO strings before binding.
  3. Upgrade the component that produced the payload — older/mismatched DCP versions may emit incompatible timestamp formats.

Example fix

// before
{ "lastUpdate": 1704067200000 }
// after
{ "lastUpdate": "2024-01-01T00:00:00.000000Z" }
Defensive patterns

Strategy: validation

Validate before calling

using var doc = JsonDocument.Parse(json);
if (doc.RootElement.TryGetProperty("lastUpdate", out var t) && t.ValueKind != JsonValueKind.String)
    throw new FormatException("lastUpdate must be an RFC3339 string, not " + t.ValueKind);

Type guard

static bool IsMicroTimeString(JsonElement e) => e.ValueKind == JsonValueKind.String && !string.IsNullOrEmpty(e.GetString());

Try / catch

try { time = JsonSerializer.Deserialize<KubernetesMicroTime>(ref reader, options); }
catch (JsonException ex) when (ex.Message.Contains("MicroTime")) { time = null; /* log and continue */ }

Prevention

When it happens

Trigger: Deserializing a DCP/Kubernetes JSON payload where a field typed as MicroTime contains a numeric epoch value or an object instead of an RFC3339 string such as "2024-01-01T12:00:00Z".

Common situations: A non-Kubernetes-compliant server or mock returning epoch milliseconds for timestamp fields; hand-edited or corrupted DCP state files; version drift between dashboard and DCP emitting different timestamp shapes.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at src/Aspire.Hosting/Dcp/Model/KubernetesMicroTimeJsonConverter.cs:24

using System.Text.Json.Serialization;

namespace Aspire.Hosting.Dcp.Model;

internal sealed class KubernetesMicroTimeJsonConverter : JsonConverter<DateTime?>
{
    private const string UtcFormat = "yyyy-MM-dd'T'HH:mm:ss.ffffff'Z'";
    private const string OffsetFormat = "yyyy-MM-dd'T'HH:mm:ss.ffffffzzz";

    public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        if (reader.TokenType is JsonTokenType.Null)
        {
            return null;
        }

        if (reader.TokenType is not JsonTokenType.String)
        {
            throw new JsonException($"Expected a string token for Kubernetes MicroTime but found {reader.TokenType}.");
        }

        var value = reader.GetString();
        if (string.IsNullOrEmpty(value))
        {
            throw new JsonException("Expected a non-empty Kubernetes MicroTime value.");
        }

        return value.EndsWith('Z')
            ? DateTime.ParseExact(value, UtcFormat, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal)
            : DateTimeOffset.ParseExact(value, OffsetFormat, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal).UtcDateTime;
    }

    public override void Write(Utf8JsonWriter writer, DateTime? value, JsonSerializerOptions options)
    {
        if (value is null)
        {
            writer.WriteNullValue();

View on GitHub (pinned to 25830f84bd)