{"record":{"id":"d623ce0842fec3b3","repo":"ory/hydra","slug":"panic-during-json-web-key-generation-for-set-q","errorCode":null,"errorMessage":"panic during JSON Web Key generation for set %q: %v","messagePattern":"panic during JSON Web Key generation for set %q: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"jwk/helper.go","lineNumber":90,"sourceCode":"\n\t// The network ID scopes the flight to one tenant. The NUL separators keep\n\t// distinct (set, kid) tuples from mapping to the same key; results are\n\t// shared between all callers on the same key, so the key must never be\n\t// ambiguous.\n\tkey := r.Networker().NetworkID(ctx).String() + \"\\x00\" + set + \"\\x00\" + kid\n\n\t// A flight is bounded by generateTimeout, so waiting much longer than that\n\t// means it died without delivering (e.g. runtime.Goexit in a test); error\n\t// out rather than blocking forever.\n\tctx, cancel := context.WithTimeout(ctx, 2*generateTimeout)\n\tdefer cancel()\n\n\tch := generateFlight.DoChan(key, func() (_ any, err error) {\n\t\t// A panic must surface as an error: singleflight would otherwise\n\t\t// crash the whole process when channel waiters are present.\n\t\tdefer func() {\n\t\t\tif e := recover(); e != nil {\n\t\t\t\terr = errors.Errorf(\"panic during JSON Web Key generation for set %q: %v\", set, e)\n\t\t\t}\n\t\t}()\n\n\t\t// The flight must not be canceled by the request that happened to\n\t\t// start it: other requests may be waiting on the result. Context\n\t\t// values (network ID, tracing) are preserved.\n\t\tfctx, cancel := context.WithTimeout(context.WithoutCancel(ctx), generateTimeout)\n\t\tdefer cancel()\n\n\t\treturn readOrGenerateKeySet(fctx, r, set, kid, alg, use)\n\t})\n\n\tselect {\n\tcase <-ctx.Done():\n\t\treturn nil, errors.WithStack(ctx.Err())\n\tcase result := <-ch:\n\t\tif result.Err != nil {\n\t\t\treturn nil, result.Err","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/ory/hydra/blob/4174065ffb052799890f7480f5360a877a67ffc1/jwk/helper.go#L72-L108","documentation":"This error converts a panic raised inside the singleflight-generated JWK creation into a normal error. Without the recover, a panic in singleflight.Do would crash the entire process, including concurrent requests waiting on the same flight. The message reports the JWK set name and the recovered panic value.","triggerScenarios":"Any panic thrown inside the flight function that generates keys for a JWK set — e.g. nil dereference in key generation, uuid.Must failing, crypto randomness unavailable, or a bug in josex.NewSigningKey — while other requests may be waiting on the same singleflight channel.","commonSituations":"Hardware/OS-level entropy failures (crypto/rand read error panics or uuid.Must panics); concurrent first-time key generation for the same set triggering a latent bug; memory exhaustion during 4096-bit RSA key generation under load.","solutions":["Inspect the %v payload in the log to identify the panicking code path inside the JWK generation flight","Fix the root cause in the key-generation code (check crypto/rand availability, memory limits for RSA 4096, uuid generation)","Retry the request — the error is transient from the caller's perspective and the flight result is not cached on panic","Reduce concurrency pressure on the same JWK set while investigating"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"keys, err := mgr.GetOrGenerateKeySet(ctx, set)\nif err != nil {\n    if strings.Contains(err.Error(), \"panic during JSON Web Key generation\") {\n        log.WithError(err).Error(\"jwk generation panicked; retrying\")\n        return retryWithBackoff(ctx, func() error { _, err := mgr.GetOrGenerateKeySet(ctx, set); return err })\n    }\n    return err\n}","preventionTips":["Log the recovered panic value to find and fix the root cause in key generation","Keep RSA bit size within memory budgets (4096-bit keys are expensive under load)","Monitor for repeated panics on the same JWK set — indicates a deterministic bug, not transient","Ensure crypto/rand and uuid generation are healthy in the deployment environment"],"tags":["panic","singleflight","jwk","concurrency"],"backgroundTag":"panic-recovered-as-error","analyzedSha":"4174065ffb052799890f7480f5360a877a67ffc1","analyzedAt":"2026-09-03T14:52:41.581Z","contentChangedAt":"2026-09-03T14:52:41.581Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}