hashicorp/nomad · error

could not encrypt: %w

Error message

could not encrypt: %w

What it means

The KMS wrapper's Encrypt call failed while encrypting data with the cipher set's root key. The underlying wrapper error (context canceled, KMS backend unavailable, invalid key state) is wrapped with 'could not encrypt'.

Source

Thrown at nomad/encrypter.go:282

	}
	return nil
}

// Encrypt encrypts the clear data with the cipher for the active root key, and
// returns the cipher text (including the nonce), and the key ID used to encrypt
// it
func (e *Encrypter) Encrypt(cleartext []byte) ([]byte, string, error) {
	cs, err := e.activeCipherSet()
	if err != nil {
		return nil, "", err
	}

	keyID := cs.rootKey.Meta.KeyID
	additional := kms.WithAad([]byte(keyID)) // include the keyID in the seal inputs

	bi, err := cs.wrapper.Encrypt(e.srv.shutdownCtx, cleartext, additional)
	if err != nil {
		return nil, "", fmt.Errorf("could not encrypt: %w", err)
	}
	return bi.Ciphertext, keyID, nil
}

// Decrypt takes an encrypted buffer and then root key ID. It extracts
// the nonce, decrypts the content, and returns the cleartext data.
func (e *Encrypter) Decrypt(ciphertext []byte, keyID string) ([]byte, error) {
	ctx, cancel := context.WithTimeout(e.srv.shutdownCtx, time.Second)
	defer cancel()
	ks, err := e.waitForKey(ctx, keyID)
	if err != nil {
		return nil, err
	}

	additional := kms.WithAad([]byte(keyID)) // keyID was included in the seal inputs
	bi := &kms.BlobInfo{
		Ciphertext: ciphertext, // nonce was stored alongside ciphertext
	}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Inspect the wrapped cause to identify the failing provider (local AEAD vs Vault transit vs cloud KMS)
  2. For remote KMS providers, verify credentials, network reachability, and IAM/key permissions
  3. Retry the operation if the server was mid-restart or the key was rotating
  4. If shutdownCtx was canceled, re-issue the request after the server is healthy

Example fix

// before: expired Vault token breaks transit encryption
//   vault token renew or fix vault config token
// after: ensure the agent's Vault config uses a renewable token / approle
//   vault {
//     address = "https://vault:8200"
//     role    = "nomad-server"
//   }
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check Vault transit reachability before encrypting
resp, err := http.Get("https://vault:8200/v1/sys/health")
if err != nil || resp.StatusCode >= 500 {
  return fmt.Errorf("vault unreachable, encryption will fail")
}

Try / catch

blob, keyID, err := encrypter.Encrypt(ctx, plaintext)
if err != nil {
  var ctxErr error
  if errors.Is(err, context.Canceled) || srvShutdownInProgress {
    ctxErr = fmt.Errorf("server shutting down, requeue work: %w", err)
  } else if isTransientKMS(err) {
    ctxErr = fmt.Errorf("transient KMS error, retry with backoff: %w", err)
  }
  return nil, ctxErr
}

Prevention

When it happens

Trigger: Encrypter.Encrypt -> encrypt -> cs.wrapper.Encrypt(shutdownCtx, cleartext, aad) returns an error; with the AEAD provider this means local cipher setup failed, with transit/cloud KMS providers it means the remote call failed. Also surfaces if the server is shutting down (shutdownCtx canceled).

Common situations: Vault transit token expired, AWS/GCP/Azure KMS network or IAM error, server shutdown in progress, or internal AEAD failure after a keyring reload raced an encryption request.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/3ee710d6b7395c7f. Report an issue: GitHub.