{"record":{"id":"5d30f5a4f48e6452","repo":"semaphoreui/semaphore","slug":"read-jwt-signing-key-option-w","errorCode":null,"errorMessage":"read jwt signing key option: %w","messagePattern":"read jwt signing key option: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"util/jwt.go","lineNumber":110,"sourceCode":"\tencrypted, err := encryptJWTKey(pemBytes)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := store.SetOption(jwtSigningKeyOption, encrypted); err != nil {\n\t\treturn nil, fmt.Errorf(\"persist signing key: %w\", err)\n\t}\n\n\treturn pemBytes, nil\n}\n\n// CheckJWTSigningKey classifies the stored JWT signing key for `vault check`:\n// \"\" (none), \"active:<id>\", \"rekey pending:<id>\", \"legacy (no id)\", or\n// \"MISSING KEY <id>\". Read-only.\nfunc CheckJWTSigningKey(store OptionStore) (slot string, err error) {\n\tstored, err := store.GetOption(jwtSigningKeyOption)\n\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\treturn Config.classifyOptionSecret(stored), nil\n}\n\n// RekeyJWTSigningKey re-encrypts the stored JWT signing key under the active\n// option key (stamping its id). It decrypts via the option keyset, the access\n// fallback, and — when supplied — oldKey (the legacy `vault rekey --old-key`\n// flow). No-op when no key is stored or the ciphertext is unchanged.\nfunc RekeyJWTSigningKey(store OptionStore, oldKey string) error {\n\tstored, err := store.GetOption(jwtSigningKeyOption)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"read jwt signing key option: %w\", err)\n\t}\n\tif stored == \"\" {\n\t\treturn nil","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/semaphoreui/semaphore/blob/1774ccb71a0a8b82eb74ea24c23ac9ab713de2fa/util/jwt.go#L92-L128","documentation":"Returned by CheckJWTSigningKey in util/jwt.go when the read-only inspection used by 'vault check' cannot load the jwt_signing_key option from the OptionStore. It is a thin wrapping guard around store.GetOption: the %w carries the underlying database error, and none of the key classification (none/active/rekey-pending/legacy/missing) could be performed because the stored value itself was unreadable.","triggerScenarios":"Thrown at util/jwt.go:110 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Check the wrapped error for the DB-level cause (connection, permissions, missing table)","Ensure migrations have created the options table before running vault check","Retry the check once the database is reachable","Confirm the DB credentials used by the CLI have read access to the options table"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"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"}