{"record":{"id":"70d9ec971ceb0fbd","repo":"semaphoreui/semaphore","slug":"jwt-failed-to-initialise-signer-w","errorCode":null,"errorMessage":"jwt: failed to initialise signer: %w","messagePattern":"jwt: failed to initialise signer: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"util/jwt.go","lineNumber":39,"sourceCode":"const jwtSigningKeyOption = \"jwt_signing_key\"\n\n// InitJWTSignerFromStore initialises the global JWT signer.\n// It must be called once after the db.Store has been opened and after ConfigInit has run.\nfunc InitJWTSignerFromStore(store OptionStore) (singer jwt.Signer, err error) {\n\tif !Config.JWT.Enabled {\n\t\treturn\n\t}\n\n\topts := jwtSignerOptions()\n\n\tpemBytes, err := loadOrCreateJWTKey(store)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"jwt: could not load or create signing key: %w\", err)\n\t}\n\n\tsigner, err := jwt.NewECDSASignerFromPEM(pemBytes, opts)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"jwt: failed to initialise signer: %w\", err)\n\t}\n\n\treturn signer, nil\n}\n\n// jwtSignerOptions builds SignerOptions from the current Config.\nfunc jwtSignerOptions() jwt.SignerOptions {\n\tttl := time.Hour\n\tif Config.JWT.DefaultTTL != \"\" {\n\t\tif parsed, err := time.ParseDuration(Config.JWT.DefaultTTL); err == nil {\n\t\t\tttl = parsed\n\t\t} else {\n\t\t\tfmt.Fprintf(os.Stderr, \"jwt: invalid jwt_default_ttl %q, falling back to 1h: %v\\n\", Config.JWT.DefaultTTL, err)\n\t\t}\n\t}\n\n\tmaxTTL := 24 * time.Hour\n\tif Config.JWT.MaxTTL != \"\" {","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/semaphoreui/semaphore/blob/1774ccb71a0a8b82eb74ea24c23ac9ab713de2fa/util/jwt.go#L21-L57","documentation":"Returned by InitJWTSignerFromStore in util/jwt.go when a signing-key PEM was obtained (loaded or newly generated) but jwt.NewECDSASignerFromPEM rejects it — for example the PEM block is missing, the key is not ECDSA, or the curve is not P-256 (the signer's own parsePrivateKey errors). The %w wraps the signer construction error, distinguishing a bad key from the key-loading failure handled one branch above.","triggerScenarios":"Thrown at util/jwt.go:39 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Inspect the wrapped signer error — 'no PEM block', 'key is not ECDSA', or 'unsupported curve' each point to a different fix","Regenerate the stored key as an ECDSA P-256 PEM and update the jwt_signing_key option (or use the rekey flow)","If the stored value was manually edited, restore the exact PEM produced by the key-generation path","Confirm JWT config options (issuer/TTLs) parse correctly so the signer options themselves are not the cause"],"exampleFix":null,"handlingStrategy":"validation","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"}