bytebase/bytebase · error

missing Azure Key Vault URL

Error message

missing Azure Key Vault URL

What it means

When resolving an external secret stored in Azure Key Vault, the component obtains Azure credentials and then reads the vault endpoint from externalSecret.Url. If Url is empty it cannot construct an azsecrets client, so getSecretFromAzure fails with 'missing Azure Key Vault URL' before any network call.

Source

Thrown at backend/component/secret/azure.go:29

	storepb "github.com/bytebase/bytebase/backend/generated-go/store"
)

func getSecretFromAzure(ctx context.Context, externalSecret *storepb.DataSourceExternalSecret) (string, error) {
	// Use default Azure credentials.
	// This supports:
	// - Environment variables (AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_TENANT_ID)
	// - Managed Identity (when running in Azure)
	// - Azure CLI credentials
	// ref: https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#DefaultAzureCredential
	cred, err := azidentity.NewDefaultAzureCredential(nil)
	if err != nil {
		return "", errors.Wrapf(err, "failed to get Azure credentials")
	}

	// The URL should be the Key Vault URL (e.g., https://myvault.vault.azure.net/)
	vaultURL := externalSecret.Url
	if vaultURL == "" {
		return "", errors.New("missing Azure Key Vault URL")
	}

	client, err := azsecrets.NewClient(vaultURL, cred, nil)
	if err != nil {
		return "", errors.Wrapf(err, "failed to create Azure Key Vault client")
	}

	// Get the secret using the secret name.
	// Empty version string means get the latest version.
	resp, err := client.GetSecret(ctx, externalSecret.SecretName, "", nil)
	if err != nil {
		if strings.Contains(err.Error(), "SecretNotFound") {
			return "", errors.Wrapf(err, "cannot find secret %s", externalSecret.SecretName)
		}
		return "", errors.Wrapf(err, "failed to get Azure Key Vault secret %s", externalSecret.SecretName)
	}

	if resp.Value == nil {

View on GitHub (pinned to 1870550677)

Solutions

  1. Set externalSecret.Url to the full Key Vault URL, e.g. https://<vault-name>.vault.azure.net/.
  2. Confirm the URL is reachable and uses https:// (azsecrets.NewClient requires a valid vault endpoint).
  3. Check that the correct provider (Azure) is selected for this secret, not AWS/GCP which use different identifiers.
  4. Re-save the ExternalSecret record and retry ReplaceExternalSecret.

Example fix

// before
{"provider": "AZURE", "url": ""}
// after
{"provider": "AZURE", "url": "https://myvault.vault.azure.net/"}
Defensive patterns

Strategy: validation

Validate before calling

if (externalSecret.provider === 'AZURE' && !externalSecret.url) {
  throw new Error('Azure external secret requires the Key Vault URL, e.g. https://myvault.vault.azure.net/')
}
await replaceExternalSecret(externalSecret)

Type guard

func azureSecretURLValid(s ExternalSecret) bool {
	return s.Provider == Azure && strings.HasPrefix(s.Url, "https://") && strings.HasSuffix(s.Url, "/")
}

Try / catch

secret, err := manager.ReplaceExternalSecret(ctx, ext)
if err != nil && strings.Contains(err.Error(), "missing Azure Key Vault URL") {
  return fmt.Errorf("external secret %q: set the vault URL field before syncing", ext.Name)
}

Prevention

When it happens

Trigger: ReplaceExternalSecret dispatches to the Azure provider but the ExternalSecret record was saved without Url populated (the Key Vault URL such as https://myvault.vault.azure.net/).

Common situations: Creating the external secret via API/UI and leaving the vault URL field blank; copying config from an AWS/GCP secret setup where no URL is needed; a migration that dropped the Url field.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of bytebase/bytebase@1870550677 (2026-09-06). Data as JSON: /api/errors/10f9e30929f4faf2. Report an issue: GitHub.