kopia/kopia · critical · errInvalidMasterKey

empty key

Error message

empty key

What it means

DeriveKeyFromMasterKey returns this when the supplied master key is empty (len == 0), wrapping the sentinel 'invalid primary key'. HKDF requires non-empty key material, so all purpose-specific derivations (AES keys, auth data, HMAC secrets) are refused early with a clear message instead of a cryptic hkdf failure.

Solutions

  1. Load/unlock the master key before any derivation call and assert it is non-empty
  2. Check the key source (env var, config, key file) is actually populated at startup
  3. Fix the unlock flow so key material is stored in the variable passed to derivation
  4. In tests, use crypto.TestDeriveKey or generate a key explicitly instead of passing nil

Example fix

// before
masterKey := os.Getenv("KOPIA_MASTER_KEY") // may be ""
derived, err := crypto.DeriveKeyFromMasterKey([]byte(masterKey), salt, purpose, 32)
// after
masterKey := os.Getenv("KOPIA_MASTER_KEY")
if masterKey == "" {
    return nil, errors.New("KOPIA_MASTER_KEY is not set")
}
derived, err := crypto.DeriveKeyFromMasterKey([]byte(masterKey), salt, purpose, 32)
Defensive patterns

Strategy: validation

Validate before calling

if len(masterKey) == 0 {
    return errors.New("master key is empty; load it before deriving subkeys")
}

Type guard

func validMasterKey(k []byte) bool { return len(k) > 0 }

Try / catch

derived, err := crypto.DeriveKeyFromMasterKey(masterKey, salt, purpose, 32)
if err != nil {
    if errors.Is(errors.Cause(err), crypto.ErrInvalidMasterKey) {
        return loadAndUnlockKey(ctx)
    }
    return fmt.Errorf("key derivation failed: %w", err)
}

Prevention

When it happens

Trigger: Calling DeriveKeyFromMasterKey (directly or via initCrypto, deriveHMACSecret, DeriveKey) with a nil or zero-length masterKey slice.

Common situations: Repository locked / never unlocked; KOPIA_PASSWORD or key env var not set; reading a key file that is empty or failed to load; unit tests forgetting to provision a test key.

Related errors


AI-assisted analysis of kopia/kopia@82495e54b5 (2026-09-07). Data as JSON: /api/errors/b07a57e126d0e175. Report an issue: GitHub.

Appendix: source

Thrown at internal/crypto/key_derivation.go:15

package crypto

import (
	"crypto/hkdf"
	"crypto/sha256"

	"github.com/pkg/errors"
)

var errInvalidMasterKey = errors.New("invalid primary key")

// DeriveKeyFromMasterKey computes a key for a specific purpose and length using HKDF based on the master key.
func DeriveKeyFromMasterKey(masterKey, salt []byte, purpose string, length int) (derivedKey []byte, err error) {
	if len(masterKey) == 0 {
		return nil, errors.Wrap(errInvalidMasterKey, "empty key")
	}

	if derivedKey, err = hkdf.Key(sha256.New, masterKey, salt, purpose, length); err != nil {
		return nil, errors.Wrap(err, "unable to derive key")
	}

	return derivedKey, nil
}

View on GitHub (pinned to 82495e54b5)