dgraph-io/dgraph · error

flags: ACL secret key set in both vault and acl flags

Error message

flags: ACL secret key set in both vault and acl flags

What it means

GetEncAclKeys resolves the ACL super-flag into a signing key. When the HMAC secret is found via the vault-sourced 'acl' super flag AND a key file path is also set (flagAclKeyFile), the key would be specified twice, so the function refuses to guess which one wins and returns this error.

Source

Thrown at x/acl_enc_keys.go:62

	encKeyFile := encSuperFlag.GetPath(flagEncKeyFile)
	if encKeyFile != "" {
		if encKey != nil {
			return nil, fmt.Errorf("flags: Encryption key set in both vault and encryption flags")
		}
		var err error
		if encKey, err = os.ReadFile(encKeyFile); err != nil {
			return nil, fmt.Errorf("error reading encryption key from file: %s: %s", encKeyFile, err)
		}
	}
	if l := len(encKey); encKey != nil && l != 16 && l != 32 && l != 64 {
		return nil, fmt.Errorf("encryption key must have length of 16, 32, or 64 bytes, got %d bytes instead", l)
	}

	aclSecretFile := aclSuperFlag.GetPath(flagAclKeyFile)
	if aclSecretFile != "" {
		if aclKey != nil {
			return nil, fmt.Errorf("flags: ACL secret key set in both vault and acl flags")
		}
		var err error
		if aclKey, err = os.ReadFile(aclSecretFile); err != nil {
			return nil, fmt.Errorf("error reading ACL secret key from file: %s: %s", aclSecretFile, err)
		}
	}

	keys := &Keys{
		AclSecretKeyBytes: aclKey,
		AclAccessTtl:      aclSuperFlag.GetDuration(flagAclAccessTtl),
		AclRefreshTtl:     aclSuperFlag.GetDuration(flagAclRefreshTtl),
		EncKey:            encKey,
	}

	if aclKey != nil {
		algStr := aclSuperFlag.GetString(flagAclJwtAlg)
		aclAlg := jwt.GetSigningMethod(algStr)
		if aclAlg == nil {

View on GitHub (pinned to 759e242be6)

Solutions

  1. Remove the ACL key-file flag (flagAclKeyFile path) so only the vault-provided key is used
  2. Or remove the ACL secret key from Vault and supply it only via the key file
  3. Audit the composed superflag string for duplicated components
  4. Restart the command after ensuring exactly one key source is configured

Example fix

// before
--acl "hmac-secret-file=/vault/secrets/acl_key;jwt-alg=HS256" # vault injects key AND file set
// after
--acl "jwt-alg=HS256" # rely solely on vault-provided hmac secret
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check your superflag composition: exactly one key source
keyFile := flagAclKeyFileValue // from your config
vaultKeySet := vaultSecretResolved != ""
if keyFile != "" && vaultKeySet {
    return fmt.Errorf("configure either key file or vault secret, not both")
}
_, err := x.GetEncAclKeys(aclSuperFlag, encKey) // fail fast at startup

Try / catch

if _, err := x.GetEncAclKeys(flag, encKey); err != nil {
    if strings.Contains(err.Error(), "set in both vault and acl flags") {
        // fix config: drop one source
    }
    return err
}

Prevention

When it happens

Trigger: Calling GetEncAclKeys (via dgraph restore/export/alpha/bulk, runRestoreCmd, runExportBackup, openDgraph, RunMapper) when both the vault-delivered acl secret key and the --acl key-file option are non-empty.

Common situations: Operators migrating from file-based ACL key config to Vault-based secrets but leaving the old file flag in place; a Helm/daemonset configmap where a leftover acl key file path duplicates a Vault-injected secret.

Related errors


AI-assisted analysis of dgraph-io/dgraph@759e242be6 (2026-09-01). Data as JSON: /api/errors/4555506be7013c21. Report an issue: GitHub.