microsoft/aspire · error · InvalidOperationException
Embedded telemetry hook script
Error message
Embedded telemetry hook script '{resourceName}' was not found in the CLI assembly. What it means
TelemetryHookInstaller.ReadEmbeddedText loads hook script text (shell/PowerShell) that is embedded as a manifest resource in the CLI assembly. This error means the resource name was not found — the assembly is missing an expected embedded script. It signals a broken or partially built/deployed CLI binary rather than a user input problem.
Solutions
- Rebuild/reinstall the CLI from official sources (or run ./build.sh / dotnet publish with default settings) so embedded resources are included.
- If you customized resource file names/namespaces, update the resourceName strings in TelemetryHookInstaller to match the actual embedded resource names.
- Disable aggressive trimming/resource stripping for the CLI publish, or verify the resource appears in the assembly's manifest.
- Run `aspire --version` to confirm you are on a complete, official build rather than a partial local artifact.
Example fix
// before // csproj omits the hook scripts from embedded resources // after <ItemGroup> <EmbeddedResource Include="Agents/Hooks/Scripts/*.sh;Agents/Hooks/Scripts/*.ps1" /> </ItemGroup>
Defensive patterns
Strategy: try-catch
Try / catch
try
{
await installer.InstallAsync(...);
}
catch (InvalidOperationException ex) when (ex.Message.StartsWith("Embedded telemetry hook script"))
{
// the CLI build is missing embedded resources; reinstall the CLI
} Prevention
- Use official CLI builds rather than partially published/trimmed local artifacts.
- After resource file renames, confirm embedded resource names match code references.
- Avoid IL trimming settings that strip EmbeddedResource entries from the CLI assembly.
When it happens
Trigger: Thrown when Assembly.GetManifestResourceStream(resourceName) returns null for a shell or PowerShell telemetry hook script — i.e. the resource was not embedded at build time, or a trimmed/published assembly dropped it.
Common situations: Running a hand-built or locally modified CLI where the .sh/.ps1 embedded resources were not included; IL trimming or single-file publish stripping resources; copying a partially built binary; mismatch between resource naming convention and code after a rename.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- MarkdownShowcase.txt embedded resource not found.
- No buildable AppHosts were found, but there may have been…
- The ' ' assembly has no informational version.
- Unable to retrieve the assembly version.
- Already connected to AppHost backchannel.
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/d99a31bc3b36bb52.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Cli/Agents/Hooks/TelemetryHookInstaller.cs:66
var powerShellContent = ReadEmbeddedText(PowerShellResourceName);
await WriteFileIfChangedAsync(shellPath, shellContent, cancellationToken);
await WriteFileIfChangedAsync(powerShellPath, powerShellContent, cancellationToken);
// Ensure the shell script is executable so a `bash <path>` (or direct exec) hook entry works.
// Spawning `chmod` would add PATH/shell failure modes, so use the platform API directly.
TrySetExecutable(shellPath);
return new TelemetryHookScripts(shellPath, powerShellPath);
}
private static string NormalizeToLf(string content)
=> content.Replace("\r\n", "\n").Replace("\r", "\n");
private static string ReadEmbeddedText(string resourceName)
{
using var stream = typeof(TelemetryHookInstaller).Assembly.GetManifestResourceStream(resourceName)
?? throw new InvalidOperationException($"Embedded telemetry hook script '{resourceName}' was not found in the CLI assembly.");
using var reader = new StreamReader(stream, s_utf8NoBom);
return reader.ReadToEnd();
}
private async Task WriteFileIfChangedAsync(string path, string content, CancellationToken cancellationToken)
{
// Skip the write when the content already matches so a running hook isn't disturbed and the
// file mtime stays stable across repeated `agent init` runs.
if (File.Exists(path))
{
try
{
var existing = await File.ReadAllTextAsync(path, s_utf8NoBom, cancellationToken);
if (string.Equals(existing, content, StringComparison.Ordinal))
{
return;
}
}View on GitHub (pinned to 25830f84bd)