{"record":{"id":"c0ddf3699254d1f4","repo":"semaphoreui/semaphore","slug":"jwt-re-encrypt-signing-key-w","errorCode":null,"errorMessage":"jwt: re-encrypt signing key: %w","messagePattern":"jwt: re-encrypt signing key: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"util/jwt.go","lineNumber":142,"sourceCode":"\tif err != nil {\n\t\treturn fmt.Errorf(\"read jwt signing key option: %w\", err)\n\t}\n\tif stored == \"\" {\n\t\treturn nil\n\t}\n\n\tpemBytes, err := Config.DecryptOption(stored)\n\tif err != nil && oldKey != \"\" {\n\t\t_, ct, _ := parseEnvelope(stored)\n\t\tpemBytes, err = DecryptAESGCM(ct, oldKey)\n\t}\n\tif err != nil {\n\t\treturn fmt.Errorf(\"jwt: decrypt signing key for rekey: %w\", err)\n\t}\n\n\treEncrypted, err := Config.EncryptOption(pemBytes)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"jwt: re-encrypt signing key: %w\", err)\n\t}\n\n\tif reEncrypted == stored {\n\t\treturn nil\n\t}\n\n\tif err := store.SetOption(jwtSigningKeyOption, reEncrypted); err != nil {\n\t\treturn fmt.Errorf(\"jwt: persist re-encrypted signing key: %w\", err)\n\t}\n\treturn nil\n}\n\n// encryptJWTKey encrypts pemBytes using the option keyring primary key (which\n// falls back to the access key when no separate option key is configured).\nfunc encryptJWTKey(pemBytes []byte) (string, error) {\n\treturn Config.EncryptOption(pemBytes)\n}\n","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/semaphoreui/semaphore/blob/1774ccb71a0a8b82eb74ea24c23ac9ab713de2fa/util/jwt.go#L124-L160","documentation":"After successfully decrypting the JWT signing key plaintext, RekeyJWTSigningKey re-encrypts it with Config.EncryptOption, which uses the option keyring primary key (falling back to the access key). This error means the re-encryption step failed, typically because no encryption key material is configured.","triggerScenarios":"Calling RekeyJWTSigningKey when the option keyring has no primary key and no access-key fallback is available - e.g. missing/unset option-key or access-key configuration at rekey time.","commonSituations":"Option key env/config removed during a rotation; running the rekey command in an environment where Config encryption keys were never set up; keyring initialized after the rekey call.","solutions":["Ensure the option keyring is configured (option key env/config, or a valid access key fallback) before running the rekey.","Initialize Config/keyring before calling RekeyJWTSigningKey in custom tooling.","Re-run the rekey once encryption keys are present - decryption already succeeded, so only the encrypt step needs a valid key."],"exampleFix":"// before\nutil.RekeyJWTSigningKey(store, oldKey) // keyring not configured in this process\n// after\nutil.LoadConfig() // sets up option/access keyrings from config/env\nif !util.Config.HasOptionKey() {\n    return errors.New(\"configure option or access key before rekey\")\n}\nutil.RekeyJWTSigningKey(store, oldKey)","handlingStrategy":"try-catch","validationCode":"// ensure encryption is configured before rekey\nif util.Config == nil || !util.Config.HasEncryptionKey() {\n    return errors.New(\"option/access encryption key not configured\")\n}","typeGuard":null,"tryCatchPattern":"if err := util.RekeyJWTSigningKey(store, oldKey); err != nil {\n    if strings.Contains(err.Error(), \"re-encrypt signing key\") {\n        return fmt.Errorf(\"no primary encryption key available for option keyring; set option key or access key fallback: %w\", err)\n    }\n    return err\n}","preventionTips":["Configure the option key (or ensure the access-key fallback exists) before key maintenance.","Initialize config/keyring before invoking rekey in scripts or custom tooling.","Keep the keyring setup identical across all environments touching the same database."],"tags":["jwt","encryption","keyring","config"],"backgroundTag":"missing-config-value","analyzedSha":"1774ccb71a0a8b82eb74ea24c23ac9ab713de2fa","analyzedAt":"2026-09-07T11:00:33.293Z","contentChangedAt":"2026-09-07T11:00:33.293Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}