{"record":{"id":"8538b736a36f8db0","repo":"passbolt/passbolt_api","slug":"the-version-is-invalid","errorCode":null,"errorMessage":"The version is invalid.","messagePattern":"The version is invalid\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"plugins/PassboltCe/JwtAuthentication/src/Authenticator/GpgJwtAuthenticator.php","lineNumber":430,"sourceCode":"    /**\n     * @param mixed $armoredChallenge challenge\n     * @throws \\InvalidArgumentException if armored challenge is invalid\n     * @return void\n     */\n    public function assertArmoredChallenge(mixed $armoredChallenge): void\n    {\n        $this->assertGpgMessageIsValid($this->gpg, $armoredChallenge, __('The user challenge is missing or invalid.'));\n    }\n\n    /**\n     * @param mixed $version version\n     * @throws \\Exception if version is not supported\n     * @return void\n     */\n    public function assertVersion(mixed $version): void\n    {\n        if (!isset($version) || !is_string($version) || $version !== self::PROTOCOL_VERSION) {\n            throw new Exception(__('The version is invalid.'));\n        }\n    }\n\n    /**\n     * Assert domain\n     *\n     * @param mixed $domain domain\n     * @return void\n     * @throws \\Passbolt\\JwtAuthentication\\Error\\Exception\\Challenge\\InvalidDomainException if domain is invalid\n     */\n    public function assertDomain(mixed $domain): void\n    {\n        if (!isset($domain) || !is_string($domain)) {\n            throw new InvalidDomainException(__('The domain is invalid.'));\n        }\n\n        if (rtrim($domain, '/') !== rtrim(Router::url('/', true), '/')) {\n            $expect = rtrim(Router::url('/', true));","sourceCodeStart":412,"sourceCodeEnd":448,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltCe/JwtAuthentication/src/Authenticator/GpgJwtAuthenticator.php#L412-L448","documentation":"assertVersion ensures the challenge's version field equals the PROTOCOL_VERSION constant supported by this authenticator. A mismatch throws a plain Exception which verifyChallenge wraps into 'The challenge is invalid. Validation Failed.' — the protocol version negotiated by the client is not supported.","triggerScenarios":"verifyChallenge on POST /auth/jwt/login where the decrypted challenge has version missing, non-string, or a value different from self::PROTOCOL_VERSION (e.g. client built for an older protocol 'v1' vs 'v2').","commonSituations":"Client SDK and passbolt server versions out of sync after a server upgrade; hand-rolled login scripts hardcoding an old version string; typo like 'V1' (case-sensitive comparison).","solutions":["Align the client SDK version with the server's passbolt version and the PROTOCOL_VERSION it expects","Set the challenge's version field exactly to the protocol constant (case-sensitive string)","Check passbolt release notes for JWT protocol version changes after upgrading the server","Inspect server logs for the logged challenge to see which version value was sent"],"exampleFix":"// before\nconst challenge = { version: 'v1', ... };\n// after (server expects PROTOCOL_VERSION 'v2')\nconst challenge = { version: 'v2', ... };","handlingStrategy":"fallback","validationCode":"if (challenge.version !== SUPPORTED_PROTOCOL_VERSION) challenge.version = SUPPORTED_PROTOCOL_VERSION; // or rebuild challenge","typeGuard":"function hasSupportedVersion(c) { return typeof c.version === 'string' && c.version === 'v2'; }","tryCatchPattern":"try { await login(challenge); } catch (e) { if (/Validation Failed/.test(e.message) && challenge.version !== 'v2') { await login({ ...challenge, version: 'v2' }); } }","preventionTips":["Read the server's advertised protocol version from /auth/verify.json when available","Keep client SDK and server on compatible releases","Use the exact lowercase version string; comparisons are strict","Add a contract test asserting the challenge version after upgrades"],"tags":["protocol-version","jwt","challenge","compatibility"],"backgroundTag":"unsupported-enum-value","analyzedSha":"31c1bbc10f32808a607fa9bd81891e898779c0bc","analyzedAt":"2026-09-17T00:04:38.960Z","contentChangedAt":"2026-09-17T00:04:38.960Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}