Try this:

ClassMethod test2()
{
  set tKP = ..%New()
  set tIdentifierSerial ##class(HS.Message.AddUpdateHubRequest).%OpenId(21986071).Identifiers
  zw tIdentifierSerial
  set tKP.IsSerial = 1
  set tKP.IsList = 1
  set tSerial tIdentifierSerial.GetObjectNext(.tKey)
  for {
    if tKey="" {quit}
    do tKP.SerialList.InsertObject(tSerial)
    set tSerial tIdentifierSerial.GetObjectNext(.tKey)
  }
  tKP.%Save()
}
SELECT JSON_ARRAYAGG(json_obj)
  FROM (SELECT TOP 5
            JSON_OBJECT(
              'Name':name
              ,'Age':age
              ,'DOB':to_char(dob,'Day DD Month YYYY')
            ) json_obj
           FROM sample.person
       )
SELECT JSON_ARRAYAGG(json_obj)
  FROM (SELECT JSON_OBJECT(
                'Name':name
                ,'Age':age
                ,'DOB':to_char(dob,'Day DD Month YYYY')
                ) json_obj
       FROM sample.person
       )
  WHERE %VID BETWEEN 1 AND 5

It is strange that the bug has not been fixed yet, because it is easy to fix it by adding one line to ##class(%JSON.Generator).GenerateMappingFromXdata():

<..>
For i=1:1:count {
  Set xdata=compiledclass.XDatas.GetAt(i)
  Set configName=xdata.Name
  If configName="" Continue ; since the Name field is required, how can it be empty?
  If xdata.MimeType'="text/xml" Continue
<..>

PS: by the way, I didn't quite understand why need to check "configName", given that "Name" is a required field. Any ideas?

For versions of Caché 5.0.x, try the following code:

#include %systemInclude

n

s list=$lb(
  "test",
  "for",
  "searching unknown strings here is a very long piece with enough characters to get a lowercase alpha as a $list marker",
  "items",
  "in",
  "aaatArGetwaaaa",
  "lists",
    $lb(
    "/subs",
    "/values",
    "nested list",
    "did you see that ""w"" before the third piece?",
    "Stuart Strickland",
    "Yaron Munz")
)

str=$$$UPPER($$cccvt^%Wpglo(list,$$$MaxStringLength,.warn))
; or
; s str=$$$UPPER($$listDump^%Wprim(list,9))

'warn {
 str=$e(str,3,$l(str)-2) ; remove << & >>
 ;s @("LIST="_str) zw LIST
 
 !,$f(str,$$$UPPER("Targetw"))
}

Result: 162

If you end up searching for globals that use $lb(), then you might find it useful:

You can convert a list to a string (and vice versa), regardless of the number of nestings. Unfortunately, I can't test this code for Caché 5.x, but I think it should work.
Here is a small example of searching for a string in a list:

#include %systemInclude

 n
 
 s list=$lb(
   "test",
   "for",
   "searching unknown strings here is a very long piece with enough characters to get a lowercase alpha as a $list marker",
   "items",
   "in",
   "aaatArGetwaaaa",
   "lists",
     $lb(
     "/subs",
     "/values",
     "nested list",
     "did you see that ""w"" before the third piece?",
     "Stuart Strickland",
     "Yaron Munz")
 )
 
 str=$$$UPPER(##class(%Utility).FormatString(list,,.overflow))
 'overflow {
   ;s @("LIST="_str) zw LIST
   
   !,$f(str,$$$UPPER("Targetw"))
 }

Result: 162

To your data storage scheme, I would like to clarify one point.
Let's say there is the following data:

Organization
ID
1
2
3
GetOrgUpdatesResponse
ID Organizations
1 2,3
2 1,2
3 1,3


If you delete ID=1 (GetOrgUpdatesResponse), then ID=2 and ID=3 (Organization) will be automatically deleted. But in this case, the rows ID=2 and ID=3 (GetOrgUpdatesResponse) will contain incorrect data and the referential integrity will be violated. Or am I wrong?