goharbor/harbor · error · Exception

secret key's length has to be 16 chars, current length: %d

Error message

secret key's length has to be 16 chars, current length: %d

What it means

Thrown by get_secret_key() in make/photon/prepare/utils/cert.py when the persisted secret file (secretkey under the shared secret dir of the data volume, e.g. <data_volume>/secret/secretkey) does not contain exactly 16 characters. Harbor uses this 16-char key as the AES encryption key for credentials (e.g. stored registry/CLAIR secrets), so a wrong length is fatal. The file is normally auto-generated by _get_secret(); a hand-made or corrupted file triggers the check. Note a trailing newline counts as a character (17).

Source

Thrown at make/photon/prepare/utils/cert.py:39

        with open(key_file, 'r') as f:
            key = f.read()
            print("loaded secret from file: %s" % key_file)
        mark_file(key_file)
        return key
    if not os.path.isdir(folder):
        os.makedirs(folder)
    key = generate_random_string(length)
    with open(key_file, 'w') as f:
        f.write(key)
        print("Generated and saved secret to file: %s" % key_file)
    mark_file(key_file)
    return key


def get_secret_key(path):
    secret_key = _get_secret(path, "secretkey")
    if len(secret_key) != 16:
        raise Exception("secret key's length has to be 16 chars, current length: %d" % len(secret_key))
    return secret_key


def get_alias(path):
    alias = _get_secret(path, "defaultalias", length=8)
    return alias

@stat_decorator
def create_root_cert(subj, key_path="./k.key", cert_path="./cert.crt"):
   rc = subprocess.call(["/usr/bin/openssl", "genrsa", "-traditional", "-out", key_path, "4096"], stdout=DEVNULL, stderr=subprocess.STDOUT)
   if rc != 0:
        return rc
   return subprocess.call(["/usr/bin/openssl", "req", "-new", "-x509", "-key", key_path,\
        "-out", cert_path, "-days", "3650", "-subj", subj], stdout=DEVNULL, stderr=subprocess.STDOUT)

def create_ext_file(cn, ext_filename):
    with open(ext_filename, 'w') as f:
        f.write("subjectAltName = DNS.1:{}".format(cn))

View on GitHub (pinned to 7b2fd08cc5)

Solutions

  1. Write exactly 16 characters with no trailing newline: printf '%s' '0123456789abcdef' > <data_volume>/secret/secretkey
  2. Or delete the file (rm <data_volume>/secret/secretkey) and re-run prepare so a valid random key is regenerated - only on first-time setups, since existing encrypted data depends on the old key
  3. For clusters, distribute the identical 16-char key to every node before prepare
  4. Verify: wc -c <secretkey> must print 16

Example fix

# on the Harbor host (before)
$ echo 'mysupersecretkey' > /data/secret/secretkey   # 17 chars incl. newline

# after
$ printf '%s' 'mysupersecretkey1' > /data/secret/secretkey   # exactly 16 chars, no newline
$ wc -c < /data/secret/secretkey
16
Defensive patterns

Strategy: type-guard

Validate before calling

import os
key_file = os.path.join(data_volume, 'secret', 'secretkey')
if os.path.isfile(key_file):
    data = open(key_file).read()
    if len(data) != 16:
        raise SystemExit('secretkey has length %d, must be 16 - fix or delete the file' % len(data))

Type guard

def has_valid_secret_key(path: str) -> bool:
    """True when the persisted secretkey is exactly 16 chars."""
    try:
        with open(path) as f:
            return len(f.read()) == 16
    except OSError:
        return False

Prevention

When it happens

Trigger: An operator manually creates or edits <data_volume>/secret/secretkey with a value whose length != 16 - including echo which appends a newline, a truncated restore, or a multi-line paste. Any subsequent prepare/install run re-reads the file and raises.

Common situations: Following old guides that say to set your own secret key; migrating data volumes where the secret file was recreated; scripts writing keys with printf vs echo differences; multi-node Harbor where each node must share the same 16-char key.

Related errors


AI-assisted analysis of goharbor/harbor@7b2fd08cc5 (2026-08-16). Data as JSON: /api/errors/242b11d378384b8a. Report an issue: GitHub.