microsoft/aspire · error · InvalidOperationException

Bicep file not found at

Error message

Bicep file not found at '{bicepPath}'. Ensure the publish step completed successfully before deploying.

What it means

Before running `rad deploy`, RadiusDeploymentPipelineStep expects the publish phase to have produced app.bicep under the environment's output directory. If the file does not exist, deployment cannot proceed, so the step logs and throws this InvalidOperationException.

Solutions

  1. Run the publish step before deploy so app.bicep is generated.
  2. Check the earlier publish step's logs for the real failure and fix it.
  3. Verify the environment's output directory (artifacts path) matches where publish wrote the Bicep; do not delete artifacts between publish and deploy.

Example fix

// before (pipeline setup)
await pipeline.RunAsync(deployStep, ...);   // publish never ran

// after
await pipeline.RunAsync(publishStep, ...);
await pipeline.RunAsync(deployStep, ...);
Defensive patterns

Strategy: validation

Validate before calling

// Ensure publish ran and produced the Bicep before deploying
var bicepPath = Path.Combine(outputDir, "app.bicep");
if (!File.Exists(bicepPath))
    throw new InvalidOperationException($"Publish must run before deploy; missing {bicepPath}");

Try / catch

try { await deployStep.ExecuteAsync(context, ct); }
catch (InvalidOperationException ex) when (ex.Message.Contains("Bicep file not found"))
{
    logger.LogError(ex, "app.bicep missing — the publish step likely failed or was skipped; inspect publish logs.");
}

Prevention

When it happens

Trigger: Calling deploy (ExecuteAsync on RadiusDeploymentPipelineStep) when the publish step that generates app.bicep did not run, failed midway, or wrote to a different output directory (e.g. PublishingContextUtils.GetEnvironmentOutputPath points elsewhere).

Common situations: Running only the deploy step in a custom pipeline without running publish first; a prior publish step failed and the pipeline continued; cleaned or deleted artifacts/ output between steps; misconfigured environment output path.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


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

Appendix: source

Thrown at src/Aspire.Hosting.Radius/Publishing/RadiusDeploymentPipelineStep.cs:530

        // Detect rad CLI availability
        var radAvailable = await DetectRadCliAsync(cancellationToken).ConfigureAwait(false);
        if (!radAvailable)
        {
            logger.LogError("The 'rad' CLI was not found on PATH. Install it from {InstallUrl}", RadInstallUrl);
            throw CreateRadCliNotFoundException();
        }

        logger.LogInformation("rad CLI detected on PATH for environment '{EnvironmentName}'", _environment.Name);

        // Resolve the output directory where Bicep was generated
        var outputDir = PublishingContextUtils.GetEnvironmentOutputPath(context, _environment);
        var bicepPath = Path.Combine(outputDir, "app.bicep");

        if (!File.Exists(bicepPath))
        {
            logger.LogError("Bicep file not found at {BicepPath}. Ensure the publish step completed successfully.", bicepPath);
            throw new InvalidOperationException(
                $"Bicep file not found at '{bicepPath}'. Ensure the publish step completed successfully before deploying.");
        }

        logger.LogInformation("Starting rad deploy with Bicep file '{BicepPath}'", bicepPath);

        // Declared outside the try so the finally can always clean up the temp secrets file, even
        // if resolving/writing it (below) fails partway.
        string? parametersFilePath = null;

        var deployTask = await context.ReportingStep.CreateTaskAsync(
            $"Deploying Radius environment '{_environment.Name}' via rad deploy...",
            cancellationToken).ConfigureAwait(false);

        try
        {
            // Resolve secret/parameter values at deploy time and write them to an owner-only
            // temporary ARM JSON parameters file. This supplies the `@secure()` Bicep params
            // emitted by publish without inlining secrets into the artifact or exposing them on the

View on GitHub (pinned to 25830f84bd)