title: ARM resource iteration failing with an empty array
body: <p>It seems that all expressions in an ARM template are evaluated up-front, so even if you have condition <code>false</code> for a resource, expressions within that resource are evaluated.</p>
  
  <p>This appears to be the case regardless of whether condition is explicitly set to <code>false</code> or if it's an expression that evaluates to <code>false</code>.</p>
  
  <p>This behavior is problematic in the case resource iteration, because expressions within the resource may refer to the <code>copyIndex()</code> of a parameter or variable. However, that parameter of variable is an empty array, evaluation of those expressions will fail with a message similar to the following -</p>
  
  <blockquote>
    <p>The language expression property array index '0' is out of bounds.. Please see <a href="https://aka.ms/arm-template-expressions" rel="nofollow noreferrer">https://aka.ms/arm-template-expressions</a> for usage details.</p>
  </blockquote>
  
  <p>Is there any way I can amend my template to work regardless of whether or not there are any resources to add?</p>
  
  <h3>Example template</h3>
  
  <p>Note that I've already had to 'hack' the <code>count</code> parameter of the <code>copy</code> object. If it's <code>0</code> (as the expression <code>length(variables('productsJArray'))</code> may evaluation to), template validation fails with the following error -</p>
  
  <blockquote>
    <p>The copy count must be a postive integer value and cannot exceed '800'.</p>
  </blockquote>
  
  <p>I feel that it's a reasonable expectation that if <code>count</code> is <code>0</code>, then no resource is added - but that's a whole different subject!</p>
  
  <pre><code>{
      "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
      "contentVersion": "1.0.0.0",
      "parameters": {
          "apiManagementServiceName": {
              "type": "string",
              "metadata": {
                  "description": "The name of the API Management instance."
              }
          },
          "productsJson": {
              "type": "string",
              "metadata": {
                  "description": "A JSON representation of the Products to add."
              }
          }
      },
      "variables": {
          "productsJArray": "[json(parameters('productsJson'))]"
      },
      "resources": [
          {
              "condition": "[greater(length(variables('productsJArray')), 0)]",
              "type": "Microsoft.ApiManagement/service/products",
              "name": "[concat(parameters('apiManagementServiceName'), '/', variables('productsJArray')[copyIndex()].name)]",
              "apiVersion": "2018-06-01-preview",
              "properties": {
                  "displayName": "[variables('productsJArray')[copyIndex()].displayName]",
                  "description": "[variables('productsJArray')[copyIndex()].description]",
                  "state": "[variables('productsJArray')[copyIndex()].state]",
                  "subscriptionRequired": "[variables('productsJArray')[copyIndex()].subscriptionRequired]",
                  "approvalRequired": "[variables('productsJArray')[copyIndex()].approvalRequired]"
              },
              "copy": {
                  "name": "productscopy",
                  "count": "[if(greater(length(variables('productsJArray')), 0), length(variables('productsJArray')), 1)]"
              }
          }
      ]
  }
  </code></pre>
  
  <h3>Example parameters file that will work</h3>
  
  <p>Note that while this may seem fine, there may be instances in which the <code>productsJson</code> parameter value is any empty array, <code>[]</code>, and this is where my issue has arisen.</p>
  
  <pre><code>{
          "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
          "contentVersion": "1.0.0.0",
          "parameters": {
                  "apiManagementServiceName": {
                          "value": "my-api-management"
                  },
                  "productsJson": {
                          "value": "[{\"name\":\"my-product\",\"displayName\":\"My Product\",\"description\":\"My product is awesome.\",\"state\":\"published\",\"subscriptionRequired\":true,\"approvalRequired\":false}]"
                  }
          }
  }
  </code></pre>
  
  <h3>Example parameters file that will fail</h3>
  
  <pre><code>{
          "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
          "contentVersion": "1.0.0.0",
          "parameters": {
                  "apiManagementServiceName": {
                          "value": "lmk-bvt-conveyorbot"
                  },
                  "productsJson": {
                          "value": "[]"
                  }
          }
  }
  </code></pre>
  
  <h1>Updated template</h1>
  
  <p>Derived from one of the suggestions by user '4c74356b41'.</p>
  
  <p>This template is generating the following error -</p>
  
  <blockquote>
    <p>Unable to process template language expressions for resource '/subscriptions/**********/resourceGroups/**********/providers/Microsoft.Resources/deployments/api-management-products' at line '1' and column '839'. 'The template function 'copyIndex' is not expected at this location. The function can only be used in a resource with copy specified.</p>
  </blockquote>
  
  <pre><code>{
          "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
          "contentVersion": "1.0.0.0",
          "parameters": {
                  "apiManagementServiceName": {
                          "type": "string",
                          "metadata": {
                                  "description": "The name of the API Management instance."
                          }
                  },
                  "productsJson": {
                          "type": "string",
                          "metadata": {
                                  "description": "A JSON representation of the Products to add."
                          }
                  }
          },
          "variables": {
                  "productsJArray": "[json(parameters('productsJson'))]"
          },
          "resources": [
                  {
                          "condition": "[greater(length(variables('productsJArray')), 0)]",
                          "type": "Microsoft.Resources/deployments",
                          "name": "api-management-products",
                          "apiVersion": "2017-05-10",
                          "properties": {
                                  "mode": "Incremental",
                                  "template": {
                                          "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
                                          "contentVersion": "1.0.0.0",
                                          "resources": [
                                                  {
                                                          "type": "Microsoft.ApiManagement/service/products",
                                                          "name": "[concat(parameters('apiManagementServiceName'), '/', variables('productsJArray')[copyIndex('productscopy')].name)]",
                                                          "apiVersion": "2018-06-01-preview",
                                                          "properties": {
                                                                  "displayName": "[variables('productsJArray')[copyIndex('productscopy')].displayName]",
                                                                  "description": "[variables('productsJArray')[copyIndex('productscopy')].description]",
                                                                  "state": "[variables('productsJArray')[copyIndex('productscopy')].state]",
                                                                  "subscriptionRequired": "[variables('productsJArray')[copyIndex('productscopy')].subscriptionRequired]",
                                                                  "approvalRequired": "[variables('productsJArray')[copyIndex('productscopy')].approvalRequired]"
                                                          },
                                                          "copy": {
                                                                  "name": "productscopy",
                                                                  "count": "[if(greater(length(variables('productsJArray')), 0), length(variables('productsJArray')), 1)]"
                                                          }
                                                  }
                                          ]
                                  }
                          }
                  }
          ]
  }
  </code></pre>