Painless scripting params.entrySet()?

If I have a document like this:

POST random/_doc/1
{
  "id": 1 
}

and i want to do:

POST random/_doc/1/_update
{
  "script": {
    "source": "
      for (entry in params.entrySet()) { 
        ctx._source[entry.getKey()] = entry.getValue();
      }
    ",
    "params": {
      "a": 1,
      "b": 2
    }, 
    "lang": "painless"
  }
}

it fails with

{
  "error": {
    "root_cause": [
      {
        "type": "remote_transport_exception",
        "reason": "[AZuCya_][172.17.0.3:9300][indices:data/write/update[s]]"
      }
    ],
    "type": "illegal_argument_exception",
    "reason": "Iterable object is self-referencing itself"
  },
  "status": 400
}

I expected entrySet() to return keys: 'a', 'b', but it seems to be returning atleast the keys: 'ctx', 'a', 'b'. If i skip the 'ctx' field, all goes as intended.

POST random/_doc/1/_update
{
  "script": {
    "source": "
       for (entry in params.entrySet()) { 
         if (entry.getKey() != \"ctx\") { 
           ctx._source[entry.getKey()] = entry.getValue() 
         }
       }
    ",
    "params": {
      "a": 1,
      "b": 2
    }, 
    "lang": "painless"
  }
}

I'm wondering why this is? Is there another method to return only the keys/values given explicitly in the params object? I can go ahead and skip 'ctx' but i dont know if there are other keys i need to skip. Thoughts?

Unfortunately the way many scripts work right now is to add these variables into the params object which was parsed from the request. This is slowly being fixed as script usages are converted to script contexts. Update scripts should get this behavior by default in 7.0: https://github.com/elastic/elasticsearch/pull/32096.

That’s great. Thanks! Can I assume for now that ctx is the only key I need to skip? It looks like it is, but this is already unexpected behavior, so I just want to be sure.

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.