{"record":{"id":"b0cc0c71c7626fbe","repo":"argoproj/argo-workflows","slug":"invalid-uid","errorCode":null,"errorMessage":"invalid uid","messagePattern":"invalid uid","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"persist/sqldb/offload_node_status_repo.go","lineNumber":213,"sourceCode":"\t\t\tAll(&records)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tx = make(map[string][]string)\n\t\tfor _, r := range records {\n\t\t\tx[r.UID] = append(x[r.UID], r.Version)\n\t\t}\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn x, nil\n}\n\nfunc (wdc *nodeOffloadRepo) Delete(ctx context.Context, uid, version string) error {\n\tif uid == \"\" {\n\t\treturn fmt.Errorf(\"invalid uid\")\n\t}\n\tif version == \"\" {\n\t\treturn fmt.Errorf(\"invalid version\")\n\t}\n\tlogCtx := wdc.log.WithFields(logging.Fields{\"uid\": uid, \"version\": version})\n\tlogCtx.Debug(ctx, \"Deleting offloaded nodes\")\n\treturn wdc.sessionProxy.With(ctx, func(s db.Session) error {\n\t\trs, err := s.SQL().\n\t\t\tDeleteFrom(wdc.tableName).\n\t\t\tWhere(db.Cond{\"clustername\": wdc.clusterName}).\n\t\t\tAnd(db.Cond{\"uid\": uid}).\n\t\t\tAnd(db.Cond{\"version\": version}).\n\t\t\tExec()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\trowsAffected, err := rs.RowsAffected()\n\t\tif err != nil {","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/argoproj/argo-workflows/blob/35bff19146f5a6ada77468c431f2624bd577e373/persist/sqldb/offload_node_status_repo.go#L195-L231","documentation":"nodeOffloadRepo.Delete refuses to issue a SQL DELETE against the offloaded-node-status table when the uid argument is the empty string. The uid identifies the workflow whose offloaded node status rows are being removed, so deleting without one would either fail or delete unintended rows. The guard exists purely to surface caller bugs early instead of producing a confusing database error.","triggerScenarios":"Calling Delete(ctx, \"\", version) on the offload node status repo — e.g. a retry/expiry path that derived the workflow uid from a nil or empty metadata field, or a caller passing an unparsed/blank UID variable.","commonSituations":"Controller cleanup code (offload expiry, workflow deletion) invoked with a workflow that never got a UID assigned; tests or custom persistence implementations passing zero-value strings; retriggered/retried workflows where uid extraction silently failed.","solutions":["Fix the caller so it obtains the real workflow uid (metadata.uid) before calling Delete","Add a guard in the caller to skip/log when uid is empty instead of calling Delete","Verify the workflow object you got the uid from was properly created (not a stub/zero struct)"],"exampleFix":"// before\nerr := offloadRepo.Delete(ctx, wf.UID, version)\n// after\nif wf.UID == \"\" {\n    return fmt.Errorf(\"workflow %s has no uid, cannot delete offloaded nodes\", wf.Name)\n}\nerr := offloadRepo.Delete(ctx, wf.UID, version)","handlingStrategy":"validation","validationCode":"if uid == \"\" {\n    return fmt.Errorf(\"cannot delete offloaded node status: workflow uid is empty\")\n}\nerr := offloadRepo.Delete(ctx, uid, version)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never pass uid fields straight from structs without checking they were populated","Log the workflow object at debug level before persistence calls","Add unit tests for persistence callers with zero-value structs"],"tags":["database","validation","persistence"],"backgroundTag":"missing-required-identifier","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"}