microsoft/aspire · error · Error
HMP1 protocol error: invalid frame length
Error message
HMP1 protocol error: invalid frame length ${length} (type=${type}). What it means
Aspire's hosting pipeline exposes a built-in Diagnostics step that dumps the dependency graph of pipeline steps for troubleshooting. The dump operates on the step data resolved (flattened/validated) during the last ExecuteAsync call, cached in _lastResolvedSteps. If no execution has happened yet, that cache is null and the library throws this InvalidOperationException instead of producing misleading empty output.
Solutions
- Execute the pipeline first by calling await pipeline.ExecuteAsync(model) before running the diagnostics step, so the resolved step data is cached.
- Verify the diagnostics call targets the same DistributedApplicationPipeline instance that executed; create a new pipeline instance loses _lastResolvedSteps.
- In tests or tooling, run ExecuteAsync inside try/catch or with a throwaway model to populate diagnostics data, then dump the graph.
- If diagnostics must run standalone, inspect the pipeline via public step enumeration APIs instead of the Diagnostics step.
Example fix
// before await diagnosticsStep.ExecuteAsync(context); // throws: no execution yet // after await pipeline.ExecuteAsync(appModel); // populates resolved step data await diagnosticsStep.ExecuteAsync(context); // now dumps dependency graph
Defensive patterns
Strategy: validation
Validate before calling
// C#: ensure the pipeline executed before diagnostics
if (pipeline.GetType().GetProperty("HasSteps") is null)
throw new InvalidOperationException("Pipeline not initialized");
await pipeline.ExecuteAsync(model); // must run before diagnostics step Type guard
bool IsPipelineExecuted(CompilationResult? lastResult) => lastResult is not null;
Try / catch
try
{
await pipeline.ExecuteAsync(model);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("No resolved pipeline data available"))
{
logger.LogWarning(ex, "Diagnostics ran before pipeline execution; run ExecuteAsync first.");
} Prevention
- Always pair diagnostics collection with a prior ExecuteAsync call on the same pipeline instance.
- Do not construct a fresh pipeline for diagnostics; reuse the executed instance.
- In CI diagnostics tooling, assert execution completed before dumping the graph.
When it happens
Trigger: Running the pipeline's diagnostics step (WellKnownPipelineSteps.Diagnostics) before ever calling DistributedApplicationPipeline.ExecuteAsync, or after recreating the pipeline instance. The diagnostics step is invoked in a context (e.g. debugging hook, --diagnostics flag path) that does not itself execute the pipeline first.
Common situations: Developers wiring up pipeline diagnostics tooling or tests that invoke the diagnostics step directly; running diagnostics in a separate process or pipeline instance from the one that executed the model; calling diagnostic dumps from app-model inspection code before publish/deploy has run.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Cannot use null in a reference expression
- Failed to send request
- getValue is only available on server-returned…
- Union value is of type
- A circular lifetime reference was detected for resource
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/6218a2def78de2b0.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Dashboard/wwwroot/js/hmp1-client.js:80
}
yield frame;
}
}
_tryReadOne() {
if (this._totalLength < HEADER_SIZE) {
return null;
}
const header = this._peek(HEADER_SIZE);
const dv = new DataView(header.buffer, header.byteOffset, HEADER_SIZE);
const type = dv.getUint8(0);
const length = dv.getInt32(1, true);
// Reject negative lengths (would desync the buffer because
// `total < HEADER_SIZE`) and absurdly large lengths (would attempt to
// allocate a multi-GiB Uint8Array which either throws inside the
// `message` handler - silently wedging the client - or OOMs the tab).
if (length < 0 || length > MAX_FRAME_PAYLOAD) {
throw new Error(`HMP1 protocol error: invalid frame length ${length} (type=${type}).`);
}
const total = HEADER_SIZE + length;
if (this._totalLength < total) {
return null;
}
const payload = this._take(total).slice(HEADER_SIZE);
return { type, payload };
}
_peek(n) {
return this._concat(n, /* consume */ false);
}
_take(n) {
return this._concat(n, /* consume */ true);
}
_concat(n, consume) {View on GitHub (pinned to 25830f84bd)