Azure Container Apps pass a json string array as Environment variable ARM Deployment template language expression evaluation failed

Adrian Ruchti 20 Reputation points
2025-01-21T07:42:48.63+00:00

Hi
I need some help with the below code. I guess it should be possible to pass an array as a string as Env Var in bicep, right?

Error
Error> Deployment template language expression evaluation failed: 'The language expression '{"tenantId":"ZZZZZZZZ-3620-4f6b-9945-c2c01d239f6a","displayName":"abc"},{"tenantId":"YYYYYYYY-215c-4470-bde5-50dbd1ad11c2","displayName":"xzy"}' is not valid: the string character '{' at position '0' is not expected.'. Please see https://aka.ms/arm-functions for usage details. '

main.parameters.json
"customerTenants": {

      ``"value":[

        ``{

          ``"tenantId": “XXXXXXXX-3620-4f6b-9945-c2c01d239f6a",

          ``"displayName": “abc”

        ``},

        ``{

          ``"tenantId": “ZZZZZZZZ-215c-4470-bde5-50dbd1ad11c2",

          ``"displayName": “x”zy

        ``}

      ``]

    ``}

main.bicep

@description('List of customer tenants with tenantId and displayName.')
 param customerTenants array =[]


var serializedCustomerTenants = string(customerTenants)

// Extract displayNames into a separate array
var displayNames = [for tenant in customerTenants: tenant.displayName]

// Combine storageContainerName with displayNames
var storageContainerNames = union([storageContainerName], displayNames)

// Extract tenantIds into a separate array
var tenantIds = [for tenant in customerTenants: tenant.tenantId]


var postgresServerName = '${prefix}-postgresql'
var postgresDatabaseName = 'postgres'
var databaseNames = union([postgresDatabaseName], displayNames)
var serializedDatabaseNames = string(databaseNames)


var webAppEnvObj = {
  POSTGRES_HOST: postgresServer.outputs.POSTGRES_DOMAIN_NAME
  POSTGRES_USERNAME: webAppIdentityName
  POSTGRES_DATABASES: serializedDatabaseNames
  CUSTOMER_TENANTS_ARRAY: serializedCustomerTenants

}

module web 'web.bicep' = {
    name: 'web'
    scope: resourceGroup
    params: {
      // Required params
      name: replace('${take(prefix,19)}-ca', '--', '-')
      location: location
      tags: tags
      identityName: webAppIdentityName
      containerAppsEnvironmentName: containerApps.outputs.environmentName
      containerRegistryName: containerApps.outputs.registryName
      exists: webAppExists
      azureContainerAppsWorkloadProfile: azureContainerAppsWorkloadProfile
      additionalEnvVars: webAppEnvObj
      allowedOrigins: allowedOrigins
      // Security / Auth
      authClientSecretName: authClientSecretName
      authClientId: authClientId
      authAuthority: authAuthority
      serverAppId: serverAppId
      serverAppSecretName: serverAppSecretName
      authTenantId: authTenantId
      secrets: containerSecrets
      envSecrets: containerEnvSecrets
      // Boolean flags
      useAuthentication: useAuthentication
      enableGlobalDocumentsAccess: enableGlobalDocumentsAccess
      // Additional param
      keyVaultName: keyVault.outputs.name
      keyVaultResourceId: keyVault.outputs.Id
    }
  }

web.bicep

module app 'core/host/container-app-upsert.bicep' = {
  name: '${serviceName}-container-app-module'
 
  params: {
    name: name
    location: location
    tags: union(tags, { 'azd-service-name': serviceName })
    identityName: webIdentity.name
    exists: exists
    workloadProfile: azureContainerAppsWorkloadProfile
    containerAppsEnvironmentName: containerAppsEnvironmentName
    containerRegistryName: containerRegistryName
    identityType: 'UserAssigned'
    containerCpuCoreCount: '1.0'
    containerMemory: '2Gi'
    allowedOrigins: allowedOrigins
    containerMinReplicas: 1
    env: union(
      env,
      additionalEnvVars,{
        AZURE_CLIENT_ID: webIdentity.properties.clientId
        APP_IDENTITY_NAME: webIdentity.name
       
      }
      )
    secrets: secrets
    envSecrets: envSecrets  
    targetPort: 8000
  }
}

container-app-upsert.bicep

var envAsArray = [
  for key in objectKeys(env): {
    name: key
    value: '${env[key]}'
  }
]




module app 'container-app.bicep' = {
  name: '${deployment().name}-update'
  params: {
    name: name
    workloadProfile: workloadProfile
    location: location
    tags: tags
    identityType: identityType
    identityName: identityName
    ingressEnabled: ingressEnabled
    containerName: containerName
    containerAppsEnvironmentName: containerAppsEnvironmentName
    containerRegistryName: containerRegistryName
    containerRegistryHostSuffix: containerRegistryHostSuffix
    containerCpuCoreCount: containerCpuCoreCount
    containerMemory: containerMemory
    containerMinReplicas: containerMinReplicas
    containerMaxReplicas: containerMaxReplicas
    daprEnabled: daprEnabled
    daprAppId: daprAppId
    daprAppProtocol: daprAppProtocol
    secrets: secrets
    keyvaultIdentities: keyvaultIdentities
    allowedOrigins: allowedOrigins
    external: external
    env: concat(envAsArray, envSecrets)
    imageName: !empty(imageName) ? imageName : exists ? existingApp.properties.template.containers[0].image : ''
    targetPort: targetPort
    serviceBinds: serviceBinds
  }
}


Error>
Deployment template language expression evaluation failed: 'The language expression '{"tenantId":"ZZZZZZZZ-3620-4f6b-9945-c2c01d239f6a","displayName":"abc"},{"tenantId":"YYYYYYYY-215c-4470-bde5-50dbd1ad11c2","displayName":"xzy"}' is not valid: the string character '{' at position '0' is not expected.'. Please see https://aka.ms/arm-functions for usage details. '

Azure Container Apps
Azure Container Apps
An Azure service that provides a general-purpose, serverless container platform.
531 questions
{count} votes

1 answer

Sort by: Most helpful
  1. Khadeer Ali 3,430 Reputation points Microsoft Vendor
    2025-02-12T13:25:31.2533333+00:00

    @Adrian Ruchti ,

    Thanks for reaching out. It seems like you're encountering an issue with passing a JSON string array as an environment variable in your Bicep template. The error message indicates that the string representation of your JSON is not being recognized correctly.

    When passing complex objects like arrays of objects in ARM templates or Bicep, you should ensure that the data structure is correctly formatted and that you're using the appropriate types. In your case, the customerTenants parameter should be defined as an array of objects, and you should not serialize it to a string if it needs to be passed as an array.

    Here's a suggestion to modify your approach:

    1. Ensure that the customerTenants parameter is defined correctly as an array of objects.
    2. When you pass this parameter to your environment variables, you may want to keep it as an array rather than converting it to a string.

    For example, instead of serializing the customerTenants array, you can directly use it in your environment object:

    var webAppEnvObj = {
      POSTGRES_HOST: postgresServer.outputs.POSTGRES_DOMAIN_NAME
      POSTGRES_USERNAME: webAppIdentityName
      POSTGRES_DATABASES: serializedDatabaseNames
      CUSTOMER_TENANTS_ARRAY: customerTenants // Keep it as an array
    }
    

    This way, you avoid the serialization issue and maintain the structure of the data as expected by the Azure Container Apps.

    If you need to pass it as a string for some reason, ensure that it is properly formatted as a JSON string. You can use json(customerTenants) to convert it to a JSON string if necessary.

    Make sure to validate the structure of your JSON and the types expected in your ARM template to avoid similar issues.


    References:

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.