Skip to content

Error handling when deploying Bicep templates in Radius #10671

@andrewmatveychuk

Description

@andrewmatveychuk

Steps to reproduce

Create and register the following resource type:

namespace: Radius.Data
types:
  mySqlDatabases:
    description: |
      # Radius.Data/mySqlDatabases

      The **Radius.Data/mySqlDatabases** Resource Type deploys a MySQL database. To deploy a new MySQL database, add the mySqlDatabases resource to the application definition Bicep file:

      ```bicep
      extension radius
      param environment string

      resource myApplication 'Applications.Core/applications@2023-10-01-preview' = { ... }

      resource database 'Radius.Data/mySqlDatabases@2025-08-01-preview' = {
          name: 'database'
          properties: {
              application: myApplication.id
              environment: environment
          }
      }
      ```

      To connect your container to the database, create a connection from the Container resource to the database as shown below:

      ```bicep
      resource frontend 'Applications.Core/containers@2023-10-01-preview' = {
          name: 'frontend'
          properties: {
              application: myApplication.id
              environment: environment
              container: {
              image: 'frontend:1.25'
              ports: {
                  web: {
                  containerPort: 8080
                  }
              }
              }
              connections: {
              mysqldb: {
                  source: database.id
              }
              }
          }
      }
      ```

      The connection automatically injects environment variables into the container for all properties from the database. The environment variables are named `CONNECTION_<CONNECTION-NAME>_<PROPERTY-NAME>`. In this example, the connection name is `mysqldb` so the environment variables will be:

      * `CONNECTION_MYSQLDB_DATABASE`
      * `CONNECTION_MYSQLDB_USERNAME`
      * `CONNECTION_MYSQLDB_PASSWORD`
      * `CONNECTION_MYSQLDB_VERSION`
      * `CONNECTION_MYSQLDB_HOST`
      * `CONNECTION_MYSQLDB_PORT`

    apiVersions:
      '2025-08-01-preview':
        schema:
          type: object
          properties:
            environment:
              type: string
              description: "(Required) The Radius EnvironmentID. Typically set by the rad CLI. Typically value should be `environment`"
            application:
              type: string
              description: "(Optional) The Radius Application ID. `myApplication.id` for example."
            database:
              type: string
              description: "(Optional) The name of the database. Assumed to be `myApplication.name` if not specified."
            username:
              type: string
              description: "(Optional) The username for connecting to the database. Assumed to be `<myApplication.name>_user` if not specified."
            version:
              type: string
              enum: ['5.7', '8.0', '8.4']
              description: "(Optional) The major MySQL server version in the X.Y format. Assumed to be 8.4 if not specified."
            tags:
              type: object
              description: "(Optional) The user-defined tags that will be applied to the resource. Default is null."
              additionalProperties:
                type: string
                description: "(Optional) Tag name."
                properties:
                  value:
                    type: string
                    description: "(Optional) Tag value."
            password:
              type: string
              description: "(Read-only) The password for connecting to the database."
              readOnly: true
            host:
              type: string
              description: "(Read-only) The host name used to connect to the database."
              readOnly: true
            port:
              type: integer
              description: "(Read-only) The port number used to connect to the the database."
              readOnly: true
          required:
          - environment

Create a corresponding recipe to provision that resource as an Azure Database for MySQLand register it in an environment with configured Azure provider:

@description('Information about what resource is calling this Recipe. Generated by Radius. For more information visit https://docs.radapp.io/reference/context-schema/ ')
param context object

@description('Name of the MySQL database. Defaults to the application name.')
param database string = context.resource.properties.?database ?? '${context.application.name}'

@maxLength(32)
@description('MySQL username. Defaults to <application-name>_user')
param username string = context.resource.properties.?username ?? '${context.application.name}_user'

@description('The major MySQL server version in the X.Y format. Defaults to the version 8.4 if not provided.')
@allowed([
  '5.7'
  '8.0'
  '8.4'
])
param version string = context.resource.properties.?version ?? '8.4'

@description('The user-defined tags that will be applied to the resource. Default is null.')
param tags object = context.resource.properties.?tags ?? {}

@description('The Radius specific tags that will be applied to the resource')
var radiusTags = {
  'radapp.io-environment': context.environment.id
  'radapp.io-application': context.application == null ? '' : context.application.id
  'radapp.io-resource': context.resource.id
}

@description('Location to deploy the resources')
var location string = resourceGroup().location

@description('Unique name for the MySQL deployment and service.')
var uniqueName = 'mysql-${uniqueString(context.resource.id, resourceGroup().id)}'

@description('The port the MySQL server listens on.')
var port = 3306

@description('MySQL server root password.')
@secure()
param root_password string = uniqueString(context.resource.id, newGuid())

resource mysqlServer 'Microsoft.DBforMySQL/flexibleServers@2024-12-30' = {
  name: uniqueName
  location: location
  tags: union(tags, radiusTags)
  sku: {
    name: 'Standard_B1ms'
    tier: 'Burstable'
  }
  properties: {
    createMode: 'Default'
    version: (version == '8.0') ? '8.0.21' : version
    administratorLogin: username
    administratorLoginPassword: root_password
    databasePort: port
    storage: {
      storageSizeGB: 32
    }
    network: {
      publicNetworkAccess: 'Enabled'
    }
  }

  resource mysqlDatabase 'databases' = {
    name: database
    properties: {
      charset: 'utf8'
      collation: 'utf8_general_ci'
    }
  }
}

output result object = {
  values: {
    host: mysqlServer.properties.fullyQualifiedDomainName
    port: mysqlServer.properties.databasePort
    database: database
    username: username
  }
  secrets: {
    #disable-next-line outputs-should-not-contain-secrets
    password: root_password
  }
}

Create and deploy the following sample Radius application:

extension radius
extension radiusResources

@description('The Radius Application ID. Injected automatically by the rad CLI.')
param application string

@description('The env ID of your Radius Environment. Set automatically by the rad CLI.')
param environment string

var port int = 3000

resource frontend 'Applications.Core/containers@2023-10-01-preview' = {
  name: 'radius-demo'
  properties: {
    application: application
    environment: environment
    container: {
      image: 'ghcr.io/radius-project/samples/demo:latest'
      ports: {
        web: {
          containerPort: port
        }
      }
      /* env: {
        WORDPRESS_DB_HOST: {
          value: '${database.properties.host}:${database.properties.port}'
        }
        WORDPRESS_DB_USER: {
          value: database.properties.username
        }
        WORDPRESS_DB_PASSWORD: {
          value: database.properties.password
        }
        WORDPRESS_DB_NAME: {
          value: database.properties.database
        }
      } */
    }
    connections: {
      mysql: {
        source: database.id
      }
    }
  }
}

resource database 'Radius.Data/mySqlDatabases@2025-08-01-preview' = {
  name: 'mysql'
  properties: {
    application: application
    environment: environment
    database: 'wp_db'
    username: 'wp_user'
    version: '8.0'
  }
}

Observed behavior

The application deploys without any errors or warnings. However, if you check the environment variables injected by the connection to the database resource, the host and port properties will be missing. You will only hit an error if you try referencing them, for example, in the commented-out section in the container environment variables section.

If you try deploying the recipe as a regular Bicep template, it will result in an error, as the databasePort property is unavailable for referencing and the template output will be empty:

New-AzResourceGroupDeployment: 12:53:38 PM - The deployment '2fabe2ab-e13e-4b2f-9b0f-363c07c2a407' failed with error(s). Showing 1 out of 1 error(s).
Status Message: The template output 'result' is not valid: The language expression property 'databasePort' doesn't exist, available properties are 'administratorLogin, storage, version, state, fullyQualifiedDomainName, createMode, network, backup, highAvailability'.. (Code:DeploymentOutputEvaluationFailed)

Desired behavior

Radius should not hide any errors or warnings from Bicep templates being deployed, and it should display them in the rad CLI command output.
Ideally, Radius should check the deployment provisioning state and throw an error if it fails.

Workaround

Manually check a Bicep-defined recipe as a regular deployment via Az CLI or Azure PowerShell. etc.

rad Version

CLI Version Information:
RELEASE   VERSION   BICEP     COMMIT
0.52.0    v0.52.0   0.37.4    446e014d749ac7e07e41bd40e0bf6c9c6e9c38cd

Control Plane Information:
STATUS     VERSION
Installed  0.52.0

Operating system

No response

Additional context

Discovered while working on the follwowing PR: radius-project/resource-types-contrib#56

AB#17479

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething is broken or not working as expectedimportantThis item is a high priority Issue we intend to address as soon as possibletriagedThis issue has been reviewed and triaged

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions