{"record":{"id":"8c3d1445d0b54b17","repo":"ory/hydra","slug":"cookiex-legacy-encode-requires-legacy-key-pairs","errorCode":null,"errorMessage":"cookiex: legacy encode requires legacy key pairs","messagePattern":"cookiex: legacy encode requires legacy key pairs","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"oryx/cookiex/cookiex.go","lineNumber":98,"sourceCode":"// character. The codec seals with a key derived from the first secret\n// and opens with keys derived from any of them, so secrets rotate by\n// prepending a new one.\nfunc New[T any](purpose string, secrets [][]byte, opts ...Option) (*Codec[T], error) {\n\tif purpose == \"\" || strings.Contains(purpose, \"|\") {\n\t\treturn nil, errors.New(\"cookiex: purpose must be non-empty and must not contain a pipe character\")\n\t}\n\tif len(secrets) == 0 {\n\t\treturn nil, errors.New(\"cookiex: at least one secret is required\")\n\t}\n\tcfg := config{maxAge: defaultMaxAge}\n\tfor _, opt := range opts {\n\t\topt(&cfg)\n\t}\n\tif cfg.maxAge < 0 {\n\t\treturn nil, errors.New(\"cookiex: max age must not be negative\")\n\t}\n\tif cfg.legacyEncode && len(cfg.legacyKeyPairs) == 0 {\n\t\treturn nil, errors.New(\"cookiex: legacy encode requires legacy key pairs\")\n\t}\n\tkeys := make([][32]byte, len(secrets))\n\tfor i, secret := range secrets {\n\t\tkey, err := hkdf.Key(sha256.New, secret, nil, kdfInfo, 32)\n\t\tif err != nil {\n\t\t\treturn nil, errors.Wrap(err, \"cookiex: cannot derive key\")\n\t\t}\n\t\tkeys[i] = [32]byte(key)\n\t}\n\treturn &Codec[T]{\n\t\tpurpose: purpose,\n\t\tkeys:    keys,\n\t\tmaxAge:  cfg.maxAge,\n\t\tlegacy:  newLegacyState(cfg, cfg.maxAge),\n\t\tnow:     time.Now,\n\t}, nil\n}\n","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/ory/hydra/blob/4174065ffb052799890f7480f5360a877a67ffc1/oryx/cookiex/cookiex.go#L80-L116","documentation":"cookiex.New requires that enabling legacy encoding (WithLegacyEncode) is accompanied by at least one legacy key pair (WithLegacyKeyPairs), because the legacy securecookie codec cannot sign/encrypt without keys. New returns this error when legacyEncode is true but legacyKeyPairs is empty.","triggerScenarios":"Calling cookiex.New(secrets...) with cookiex.WithLegacyEncode(true) (or equivalent) and no WithLegacyKeyPairs(...) option, so cfg.legacyKeyPairs has length 0.","commonSituations":"Migrating from the old securecookie-based format and enabling legacy encoding without copying over the previous key pairs; loading key pairs from env/config that came back empty; conditional wiring where the legacy option is set but the key-pair option is skipped.","solutions":["Pass at least one key pair via WithLegacyKeyPairs, e.g. cookiex.WithLegacyKeyPairs([][]byte{oldHashKey, oldBlockKey}).","If legacy encoding is not needed, remove the WithLegacyEncode option.","Load the legacy key pairs from config at startup and log/fail if they are empty before calling New."],"exampleFix":"// before\ncc, err := cookiex.New([][]byte{secret}, cookiex.WithLegacyEncode(true))\n// after\ncc, err := cookiex.New([][]byte{secret},\n  cookiex.WithLegacyEncode(true),\n  cookiex.WithLegacyKeyPairs([][]byte{hashKey, blockKey}))","handlingStrategy":"validation","validationCode":"if len(legacyKeyPairs) == 0 {\n  return errors.New(\"legacy encode requested but no legacy key pairs configured\")\n}\ncc, err := cookiex.New(secrets,\n  cookiex.WithLegacyEncode(true),\n  cookiex.WithLegacyKeyPairs(legacyKeyPairs))","typeGuard":null,"tryCatchPattern":"cfg, err := cookiex.New(secrets, opts...)\nif err != nil {\n  log.Fatalf(\"cookiex configuration invalid: %v\", err)\n}","preventionTips":["Pair WithLegacyEncode with WithLegacyKeyPairs in a single helper so they cannot drift","Check env/config for legacy keys at boot when migration mode is on","Disable legacy encode once migration completes to remove the requirement"],"tags":["cookies","configuration","legacy","keys"],"backgroundTag":"missing-required-config","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"}