Skip to content

azure_ai_search dependent resource fails when storage is not also requested #62

Description

@rogerbarreto

Summary

When provisioning Azure AI Search as a dependent resource (via AI_PROJECT_DEPENDENT_RESOURCES containing {"resource":"azure_ai_search","connectionName":"search"}), infra/core/search/azure_ai_search.bicep requires a co-provisioned storage account and silently fails when one is not also requested.

The bicep takes storageAccountResourceId as a required param and uses it for an existing Storage Account reference plus a Storage Blob Data Reader role assignment and a knowledge container. If the consumer only requests azure_ai_search (not also storage), infra/main.bicep passes an empty string for storageAccountResourceId, which makes the existing reference resolve to last(split('', '/')) → empty name and the deployment fails.

Why this matters

The companion azd ai agent init flow in Azure/azure-dev (init.go ToolKindAzureAiSearch block) only auto-prompts for two tool ids when scanning the agent manifest:

if toolResource.Id == "bing_grounding" || toolResource.Id == "azure_ai_search" {
    // prompt for connection name, append to project.Resource entries
}

There is no auto-prompt for storage, so an agent author who declares kind: tool / id: azure_ai_search in their agent.manifest.yaml ends up with a generated azure.yaml that requests only azure_ai_search → provision blows up.

End users have to manually edit the generated azure.yaml after azd ai agent init and append a storage entry, which is fragile and surprising. We hit this in microsoft-foundry/foundry-samples-pr#283 (Azure AI Search RAG sample for .NET Agent Framework).

Repro

  1. Author an agent.manifest.yaml with kind: tool / id: azure_ai_search (no storage).
  2. azd ai agent init -m <manifest> (accept the prompt for the search connection name).
  3. azd provision.
  4. Bicep deployment of azure-ai-search module fails resolving the existing storage account.

Proposed fix (pick one)

Option A: Make storage optional in azure_ai_search.bicep. Skip the Storage Blob Data Reader role assignment and the knowledge container creation when storageAccountResourceId is empty:

@description('Optional. Azure storage account resource ID for the search-to-storage indexer scenario. When empty, the search-to-storage RBAC and knowledge container are skipped.')
param storageAccountResourceId string = ''

// gate the existing storage reference + container + role assignment behind a non-empty check
var hasStorage = !empty(storageAccountResourceId)

resource storageAccount '...' existing = if (hasStorage) {
  name: last(split(storageAccountResourceId, '/'))
}

resource storageContainer '...' = if (hasStorage) { ... }
resource searchToStorageRoleAssignment '...' = if (hasStorage) { ... }

This matches how ai-project.bicep already gates the azureAiSearch module behind hasSearchConnection and how it treats other dependent resources as independent.

Option B: In Azure/azure-dev, also auto-add a storage dependent resource whenever azure_ai_search is requested. Less ideal because (1) it forces a Storage Account on agents that don't need indexer scenarios, and (2) it puts knowledge of starter internals into the extension.

Option C: Both. Make storage optional in the bicep (Option A) and have the extension auto-pair them only when the user actually wants the indexer scenario (future azd ai agent init UX, e.g. a follow-up prompt).

Option A is the smallest, most local fix and unblocks the manifest-only flow today. Happy to send a PR if that direction is preferred.

Workaround (for users hitting this today)

After azd ai agent init, manually append storage to the agent service's resources: array in the generated azure.yaml:

services:
  <agent-name>:
    config:
      resources:
        - resource: azure_ai_search
          connectionName: search
        - resource: storage
          connectionName: storage

Context

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions