DeploymentNotFound error using Azure Bicep modules

Did you ever have the DeploymentNotFound error when using Azure Bicep without any syntax errors? I had the same problem. In this blog post, I will tell you more about the DeploymentNotFound error, its causes, and how to fix it.

Example Bicep template

To demonstrate and simulate the DeploymentNotFound error, I created a Bicep file with three modules: Module A, B, and C:

  • ModuleA is a module without a dependency
  • ModuleB has a dependency with ModuleA and is deployed conditionally
  • ModuleC has a dependency with ModuleB

Figure 1. Schema of Bicep modules with dependencies

Figure 1 translates to this Bicep code output:

param parDeployModuleB bool = false
module moduleA 'ModuleA.Bicep' = {
name: 'deploy-module-a'
}
module moduleB 'ModuleB.bicep' = if (parDeployModuleB) {
name: 'deploy-module-b-${uniqueString(moduleA.name)}'
params: {
parUseModuleAOutputs: moduleA.outputs.outModuleA
}
}
module moduleC 'ModuleC.bicep' = {
name: 'deploy-module-c-${uniqueString(moduleB.name)}'
params: {
parUseModuleBOutputs: moduleB.outputs.outModuleB
}
}
view raw moduleABC.bicep hosted with ❤ by GitHub

This Bicep snippet will fail during deployment, although it is syntactically correct. In the code, you can see that ModuleC has an implicit dependency with ModuleB. At first glance, this may not appear to be an issue however, you should have to take into account that ModuleB is conditionally deployed. This means that if parDeployModuleB is set to false the deployment ModuleB will never exist. This will cause issues with the deployment of ModuleC because it’s referencing the deployment name that ModuleB generates. Deploying the code from figure 1 will result in the DeploymentNotFound error:

{
"status": "Failed",
"error": {
"code": "DeploymentFailed",
"message": "At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/DeployOperations for usage details.",
"details": [
{
"code": "NotFound",
"message": "{\r\n \"error\": {\r\n \"code\": \"DeploymentNotFound\",\r\n \"message\": \"Deployment 'deploy-module-b-uzxmwqy25sh6u' could not be found.\"\r\n }\r\n}"
}
]
}
}

DeploymentNotFound error explained

Before diving into details about the DeploymentNotFound error it is good to understand how the Azure Resource Manager works. The resource manager does not deploy the Bicep file. Before the resource manager starts with the deployment, the Bicep file is transpiled to JSON. During transpiling the resource manager transforms code that is written in language A to language B so that Azure can use it in the backend. To transpile a Bicep file on your own computer run the az bicep build command, which requires the Azure CLI tooling.

I transpiled the Bicep snippet of figure 1 to JSON. Because of the length of the JSON file (134 lines of code) I have uploaded it on my GitHub Gists. To explain the origin of the error I want to zoom in on a particular section of the JSON file: the parameter usage of module output of ModuleB used in ModuleC:

JSON

"parameters": {
"parUseModuleBOutputs": {
"value": "[reference(resourceId('Microsoft.Resources/deployments', format('deploy-module-b-{0}', uniqueString('deploy-module-a'))), '2020-10-01').outputs.outModuleB.value]"
}
},

Bicep

module moduleC 'ModuleC.bicep' = {
name: 'deploy-module-c-${uniqueString(modB.name)}'
params: {
parUseModuleBOutputs: modB.outputs.outModuleB
}
}

In the snippets above the Bicep and JSON variants of dependencies to resources are shown. These snippets are from ModuleC in which they have a dependency to ModuleB. The JSON snippet shows the usage of the reference() function. This function allows to retrieve a runtime state of a resource. In this case, the function tries to refer to Microsoft.Resource/deployments with the deployment name of ModuleB. In Bicep this function is abstracted and implicitly written by using the symbolic name of a module or resource: moduleB.outputs.outModuleB.

During the deployment of ModuleC the reference() function causes the DeploymentNotFound error. The function tries to retrieve the state of ModuleB and cannot find it due to the false condition for the deployment of ModuleB. This condition prevents the Azure Resource Manager from finding the necessary deployment information.

DeploymentNotFound fix

To fix the error there are two ways:

  • Either make sure to always deploy ModuleB, so that the reference to the deployment always exists;
  • Or add a ternary expression (shorthand if) to the parUseModuleBOutputs in ModuleC like this:
module moduleC 'ModuleC.bicep' = {
name: 'deploy-module-c-${uniqueString(moduleB.name)}'
params: {
parUseModuleBOutputs: parDeployModuleB ? moduleB.outputs.outModuleB : ''
}
}

By adding a ternary expression (condition ? true : false) the Azure Resource Manager checks in runtime if the parameter parDeployModuleB is either true or false. If the parameter is false, the empty string ’’ is used instead of the reference() method when the parameter is true. 

Condition on the module

module moduleC 'ModuleC.bicep' = if (parDeployModuleB) {
name: 'deploy-module-c-${uniqueString(moduleB.name)}'
params: {
parUseModuleBOutputs: moduleB.outputs.outModuleB
}
}

Adding a condition on the module ModuleC won’t suffice. The reason for this is that the resource manager still validates the reference to ModuleB

Conclusion

In the examples above I demonstrated how to fix the DeploymentNotFound error. As you can see Bicep has a lot of abstracted code. It can be unclear what to do when the Bicep is syntactically correct, but the deployment output is an error. When Bicep errors like these are unclear, always check the transpiled version of your Bicep this may uncover more information on why a deployment fails.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s