{"record":{"id":"1b62e41645fc1343","repo":"argoproj/argo-workflows","slug":"malformed-cache-entry-could-not-unmarshal-json-u","errorCode":null,"errorMessage":"malformed cache entry: could not unmarshal JSON; unable to parse: %w","messagePattern":"malformed cache entry: could not unmarshal JSON; unable to parse: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"workflow/controller/cache/configmap_cache.go","lineNumber":117,"sourceCode":"\t\treturn nil, err\n\t}\n\terr = c.validateConfigmap(ctx, cm)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tc.logInfo(ctx, logging.Fields{}, \"config map cache loaded\")\n\thitTime := time.Now()\n\trawEntry, ok := cm.Data[key]\n\tif !ok || rawEntry == \"\" {\n\t\tc.logInfo(ctx, logging.Fields{}, \"config map cache miss: entry does not exist\")\n\t\treturn nil, nil\n\t}\n\n\tvar entry Entry\n\terr = json.Unmarshal([]byte(rawEntry), &entry)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"malformed cache entry: could not unmarshal JSON; unable to parse: %w\", err)\n\t}\n\n\tentry.LastHitTimestamp = metav1.Time{Time: hitTime}\n\tentryJSON, err := json.Marshal(entry)\n\tif err != nil {\n\t\tc.logError(ctx, err, logging.Fields{\"key\": key}, \"Unable to marshal cache entry with last hit timestamp\")\n\t\treturn nil, fmt.Errorf(\"unable to marshal cache entry with last hit timestamp: %w\", err)\n\t}\n\tcm.Data[key] = string(entryJSON)\n\n\t_, err = c.kubeClient.CoreV1().ConfigMaps(c.namespace).Update(ctx, cm, metav1.UpdateOptions{})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &entry, nil\n}\n\nfunc (c *configMapCache) Save(ctx context.Context, key string, nodeID string, value *wfv1.Outputs) error {","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/argoproj/argo-workflows/blob/35bff19146f5a6ada77468c431f2624bd577e373/workflow/controller/cache/configmap_cache.go#L99-L135","documentation":"When loading a memoization entry from a ConfigMap, the stored JSON string is unmarshalled into cache.Entry. If the ConfigMap data value is not valid JSON or does not match the Entry schema, the load fails with this wrapped parse error so the controller does not silently treat corrupted data as a cache hit.","triggerScenarios":"cm.Data[key] was written by hand or by another tool with non-JSON content; entry JSON was truncated (ConfigMap size edits, manual kubectl edit); the Entry struct changed between Argo versions so old entries no longer unmarshal.","commonSituations":"Manually editing the memoization ConfigMap; migrating from an older Argo version with a different entry schema; another controller or script sharing the same ConfigMap and writing raw strings; truncated entries after ConfigMap size limits.","solutions":["kubectl get cm <cache-cm> -o jsonpath='{.data.<key>}' and validate the value parses as JSON with the Entry fields (ExitCode, NodeID, CreationTimestamp, LastHitTimestamp).","Delete the corrupted key from the ConfigMap so the memoized node re-executes and re-saves a fresh entry.","If all entries are stale-schema, delete the whole ConfigMap (memoization entries are safe to rebuild).","Verify no external tooling writes to memoization ConfigMaps (label selector: workflows.argoproj.io/workflow).","Pin/upgrade the Argo version consistently so schema matches entries on disk."],"exampleFix":"// before: manually written entry\ncm.Data[\"key\"] = \"done\"\n// after: valid JSON entry\nimport encjson \"encoding/json\"\nb, _ := encjson.Marshal(controllercache.Entry{NodeID: \"abc\", ExitCode: \"0\", CreationTimestamp: metav1.Now(), LastHitTimestamp: metav1.Now()})\ncm.Data[\"key\"] = string(b)","handlingStrategy":"validation","validationCode":"const raw = cm.data?.[key];\ntry { const e = JSON.parse(raw); if (!('nodeID' in e) && !('exitCode' in e)) throw new Error('not an Entry'); } catch { console.warn(`corrupt cache entry for key ${key}; delete it before lookup`); }","typeGuard":"function isCacheEntry(raw) {\n  if (typeof raw !== 'string') return false;\n  try { const e = JSON.parse(raw); return e && typeof e === 'object' && 'nodeID' in e; } catch { return false; }\n}","tryCatchPattern":"try {\n  entry, err := cache.Load(ctx, key)\n  if err != nil {\n    var parseErr *json.SyntaxError\n    if errors.As(err, &parseErr) || strings.Contains(err.Error(), \"could not unmarshal JSON\") {\n      // treat as cache miss: delete corrupt key, let node re-execute\n    } else { return err }\n  }\n}","preventionTips":["Never hand-edit memoization ConfigMaps; use kubectl patch only to remove bad keys.","Keep Argo controller version consistent with entries on disk across upgrades.","Prevent other tools from writing to ConfigMaps matched by memoization labels.","Alert on this error early — it permanently blocks GC for that ConfigMap until fixed."],"tags":["memoization","cache","json"],"backgroundTag":"malformed-cache-entry","analyzedSha":"35bff19146f5a6ada77468c431f2624bd577e373","analyzedAt":"2026-09-03T19:34:35.908Z","contentChangedAt":"2026-09-03T19:34:35.908Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}