microsoft/aspire · error · InvalidOperationException

Could not read a valid start time for monitor process

Error message

Could not read a valid start time for monitor process {processId} from '{procRoot}'.

What it means

On Linux, the DCP watchdog reads the process start time from /proc/<pid>/stat (boot-relative start ticks, field 22) via a shared ProcessStartTimeHelper. If the value cannot be read or parsed (process gone, /proc unavailable, malformed stat), this InvalidOperationException is thrown instead of using a bogus timestamp that could misidentify a recycled PID.

Solutions

  1. Ensure /proc is mounted and readable for the target PID in the container/environment
  2. Check security policies (seccomp, AppArmor, SELinux) that block reading /proc/<pid>/stat and relax them for the AppHost process
  3. Re-run the AppHost if it was a transient race with process exit
Defensive patterns

Strategy: fallback

Validate before calling

static bool CanReadProcStat(int pid, string procRoot = "/proc")
    => File.Exists($"{procRoot}/{pid}/stat");

Type guard

bool ProcStatReadable(int pid) => OperatingSystem.IsLinux() && File.Exists($"/proc/{pid}/stat");

Try / catch

try
{
    var ts = DcpProcessMonitor.GetMonitorProcessIdentity(parentProcess);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("/proc"))
{
    // Disable watchdog or remount /proc readable, then retry.
}

Prevention

When it happens

Trigger: Running the AppHost on Linux when ProcessStartTimeHelper.TryGetLinuxProcessStartTicks fails: the monitor process already exited, /proc is not mounted or is restricted (hardened containers, seccomp), or the procRoot path is wrong.

Common situations: Running Aspire inside minimal/stripped containers without /proc; AppArmor/SELinux policies blocking /proc/<pid>/stat reads; PID namespace mismatches where the target PID is not visible.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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

Appendix: source

Thrown at src/Aspire.Hosting/Dcp/DcpProcessMonitor.cs:61

        {
            return null;
        }
    }

    private static DateTime GetLinuxProcessIdentityTimestamp(int processId)
    {
        // DCP inspects the *host* process table, so honor HOST_PROC when this check runs inside a
        // container whose host /proc is mounted elsewhere. Orphan/liveness detection deliberately uses the
        // current namespace's /proc instead (see ProcessStartTimeHelper.TryGetProcessStartTime), which is
        // why the /proc root is a parameter of the shared reader rather than baked into it.
        var procRoot = Environment.GetEnvironmentVariable("HOST_PROC") ?? "/proc";

        // Share the /proc start-ticks reader with every other Aspire watchdog so there is one Linux
        // process-identity implementation. The value is boot-relative (field 22 of /proc/<pid>/stat),
        // which is why it is immune to wall-clock drift.
        if (ProcessStartTimeHelper.TryGetLinuxProcessStartTicks(processId, procRoot) is not { } startTicks)
        {
            throw new InvalidOperationException($"Could not read a valid start time for monitor process {processId} from '{procRoot}'.");
        }

        // Convert the boot-relative start ticks into a DateTime offset from DateTime.MinValue instead of
        // estimating a wall-clock time. Kept in milliseconds for parity with the timestamp DCP compares
        // against, which is a distinct identity domain from the whole-second value used by the orphan
        // detectors, so the two never cross-compare.
        var startTimeMilliseconds = (startTicks * 1000) / (ulong)ProcessStartTimeHelper.GetLinuxClockTicksPerSecond();
        return DateTime.SpecifyKind(DateTime.MinValue, DateTimeKind.Utc).AddMilliseconds(startTimeMilliseconds);
    }
}

View on GitHub (pinned to 25830f84bd)