{"record":{"id":"a1025213716d270f","repo":"ory/hydra","slug":"cookiex-payload-must-be-a-flat-json-object-with-s","errorCode":null,"errorMessage":"cookiex: payload must be a flat JSON object with string values while legacy encode is enabled","messagePattern":"cookiex: payload must be a flat JSON object with string values while legacy encode is enabled","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"oryx/cookiex/legacy_securecookie.go","lineNumber":125,"sourceCode":"// payload are coerced to empty strings by the bridge; do not use pointer-typed\n// fields while legacy encode is enabled.\nfunc WithLegacyEncode() Option {\n\treturn func(c *config) { c.legacyEncode = true }\n}\n\n// sealLegacy bridges T through its JSON representation into the flat\n// string-to-string map that the securecookie stores used.\nfunc (c *Codec[T]) sealLegacy(name string, value T) (string, error) {\n\tbuf, err := json.Marshal(value)\n\tif err != nil {\n\t\treturn \"\", errors.Wrap(err, \"cookiex: cannot marshal cookie value\")\n\t}\n\tvar flat map[string]string\n\tif err := json.Unmarshal(buf, &flat); err != nil {\n\t\treturn \"\", errors.Wrap(err, \"cookiex: payload must be a flat JSON object with string values while legacy encode is enabled\")\n\t}\n\tif flat == nil {\n\t\treturn \"\", errors.New(\"cookiex: payload must be a flat JSON object with string values while legacy encode is enabled\")\n\t}\n\tvalues := make(map[any]any, len(flat))\n\tfor k, v := range flat {\n\t\tvalues[k] = v\n\t}\n\tencoded, err := securecookie.EncodeMulti(name, values, c.legacy.codecs[0])\n\tif err != nil {\n\t\treturn \"\", errors.Wrap(err, \"cookiex: cannot encode legacy cookie\")\n\t}\n\treturn encoded, nil\n}\n","sourceCodeStart":107,"sourceCodeEnd":137,"githubUrl":"https://github.com/ory/hydra/blob/4174065ffb052799890f7480f5360a877a67ffc1/oryx/cookiex/legacy_securecookie.go#L107-L137","documentation":"When legacy encode mode is enabled, sealLegacy serializes the cookie payload and unmarshals it into map[string]string to feed the legacy securecookie codec. If the JSON round-trip fails (values are not all strings) or the map is nil, this error is returned because the legacy format can only encode flat string-valued objects.","triggerScenarios":"Calling Set (which delegates to sealLegacy) on a cookiex codec created with WithLegacyEncode(true), passing a values map whose JSON contains non-string values (numbers, booleans, nested objects, arrays) or when the payload unmarshals to a nil map.","commonSituations":"Migrating an app that previously stored ints/bools in session cookies (e.g. \"count\": 42) onto cookiex with legacy encode on; storing nested structures that the old encoder silently accepted via gob but this path rejects.","solutions":["Convert all payload values to strings before Set: use strconv.Itoa/FormatBool or fmt.Sprint for each value.","Store nested/structured data as a single JSON-encoded string value.","If non-string values are required, disable WithLegacyEncode and use the modern codec path.","Use errors.As/Is on the wrapped json.Unmarshal error to distinguish a malformed payload from the nil-map case."],"exampleFix":"// before\nvals := map[string]any{\"count\": 42}\nc.Set(w, \"sess\", vals)\n// after\nvals := map[string]any{\"count\": strconv.Itoa(42)}\nc.Set(w, \"sess\", vals)","handlingStrategy":"validation","validationCode":"func stringifyValues(in map[string]any) (map[string]any, error) {\n  out := make(map[string]any, len(in))\n  for k, v := range in {\n    s, ok := v.(string)\n    if !ok { return nil, fmt.Errorf(\"cookie value %q is not a string\", k) }\n    out[k] = s\n  }\n  return out, nil\n}\n// apply before c.Set while legacy encode is enabled","typeGuard":null,"tryCatchPattern":"if _, err := c.Set(w, name, vals); err != nil {\n  var se *json.SyntaxError\n  if errors.As(err, &se) || strings.Contains(err.Error(), \"flat JSON object\") {\n    return fmt.Errorf(\"cookie payload has non-string values: %w\", err)\n  }\n  return err\n}","preventionTips":["Convert numeric/bool payload fields to strings with strconv before Set","Keep nested structures JSON-encoded inside a single string value","Remember the legacy path only supports map[string]string; test payloads during migration"],"tags":["cookies","json","legacy","type-mismatch"],"backgroundTag":"json-type-mismatch","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"}