passbolt/passbolt_api · critical · Cake\Http\Exception\InternalErrorException

The config for the server private key fingerprint is not…

Error message

The config for the server private key fingerprint is not available or incomplete.

What it means

assertServerFingerprint validates that the configured server private key fingerprint is a string passing PublicKeyValidationService::isValidFingerprint. It throws InternalErrorException (500) because a missing/invalid server fingerprint is a server configuration problem, not a client mistake.

Solutions

  1. Set passbolt.gpg.serverKey.fingerprint in config/passbolt.php or passbolt.json to the full 40-character uppercase fingerprint
  2. Run `gpg --list-keys --fingerprint | grep -i passbolt` as the web server user and copy the fingerprint exactly
  3. Ensure the env variable (e.g. PASSBOLT_GPG_SERVER_KEY_FINGERPRINT) is defined in the deployment environment
  4. Re-run the server key import step (`passbolt install` key import or gpg --import serverkey.asc)`
  5. Run `ddev refresh` / `passbolt healthcheck` to confirm the server key config check passes

Example fix

// before config/passbolt.php
'serverKey' => ['fingerprint' => null],
// after
'serverKey' => ['fingerprint' => getenv('PASSBOLT_GPG_SERVER_KEY_FINGERPRINT')], // e.g. '0FC3E17C88AE067DD66B2D5A0B9BD6D9FA2C1A2F'
Defensive patterns

Strategy: validation

Validate before calling

const fp = config.passbolt.gpg.serverKey.fingerprint;
if (typeof fp !== 'string' || !/^[A-F0-9]{40}$/.test(fp)) throw new Error('server key fingerprint config missing/invalid');

Type guard

function hasValidFingerprint(v) { return typeof v === 'string' && /^[0-9A-F]{40}$/.test(v); }

Try / catch

try { await login(); } catch (e) { if (e.status === 500 && /fingerprint is not available/.test(e.message)) { await runServerKeySetup(); } }

Prevention

When it happens

Trigger: setServerKey runs during GPG JWT authentication bootstrap when passbolt.json / passbolt.php lacks passbolt.gpg.serverKey.fingerprint, or the value is not a valid 40-char hex fingerprint.

Common situations: Fresh install where `passbolt create_user`/key install steps were skipped; config import lost the serverKey block; fingerprint pasted with spaces or lowercase/short form; env var PASSBOLT_GPG_SERVER_KEY_FINGERPRINT not set in container.

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 passbolt/passbolt_api@31c1bbc10f (2026-09-17). Data as JSON: /api/errors/1f4971cf1b5f9d3d. Report an issue: GitHub.

Appendix: source

Thrown at plugins/PassboltCe/JwtAuthentication/src/Authenticator/GpgJwtAuthenticator.php:362

            );
        } catch (Exception $exception) {
            Log::error($exception->getMessage() . "\n" . $clearTextChallenge);
            throw new BadRequestException(__('The challenge is invalid. Validation Failed.'));
        }

        return $verifyToken;
    }

    /**
     * @param mixed $fingerprint fingerprint
     * @throws \Cake\Http\Exception\InternalErrorException
     * @return void
     */
    public function assertServerFingerprint(mixed $fingerprint): void
    {
        if (!is_string($fingerprint) || !PublicKeyValidationService::isValidFingerprint($fingerprint)) {
            $msg = __('The config for the server private key fingerprint is not available or incomplete.');
            throw new InternalErrorException($msg);
        }
    }

    /**
     * @param mixed $passphrase passphrase
     * @throws \Cake\Http\Exception\InternalErrorException
     * @return void
     */
    public function assertServerPassphrase(mixed $passphrase): void
    {
        if (!is_string($passphrase)) {
            $msg = __('The config for the server private key passphrase is invalid.');
            throw new InternalErrorException($msg);
        }
    }

    /**
     * @param mixed $userId uuid

View on GitHub (pinned to 31c1bbc10f)