Search code examples
elasticsearchelasticsearch-painless

Null pointer exception in ES painless script?


I am using painless script in ES and encountering a null pointer exception, here is my script and also I have added the response for better understanding, I use ES v7.3.

POST test_script/_update/1
{
  "scripted_upsert": true,
  "script": {
    "lang": "painless",
    "source": "int getBrowsersObjectIndex(def x, def y){for (int i = 0; i < x.length; i++) {if (x[i].deviceType == y.deviceType) {if (x[i].osName == y.osName) {if(x[i].browserName == y.browserName) {return i}}}}return -1} int getDevicesObjectIndex(def x, def y){for (int i = 0; i < x.length; i++) {if (x[i].deviceId == y.deviceId) {if (x[i].appName == y.appName) {if (x[i].appNameSpace == y.appNameSpace){return i}}}}return -1}if (!ctx._source.containsKey('browsers')) {ctx._source['browsers'] = []}if (!ctx._source.containsKey('devices')) {ctx._source['devices'] = []}for (int index = 0; index < params.iterate.length; index++) {if (params.iterate[index].browserObject) {int browserIndex = getBrowsersObjectIndex(ctx._source.browsers, params.iterate[index].browserObject);if (browserIndex >= 0) {ctx._source.browsers.remove(browserIndex);}ctx._source.browsers.add(params.iterate[index].browserObject);}if (params.iterate[index].deviceObject) {int deviceIndex = getDevicesObjectIndex(ctx._source.devices, params.iterate[index].deviceObject);if (deviceIndex >= 0) {ctx._source.devices.remove(deviceIndex);}ctx._source.devices.add(params.iterate[index].deviceObject);}}",
    "params": {
      "iterate": [
        {
          "deviceObject": {
            "deviceId": "162c04e48832e338",
            "appName": "test_app",
            "appNameSpace": "com.test",
            "appBuild": 55,
            "appVersion": "4.6.3",
            "deviceName": "OP4B80L1",
            "manufacturer": "OPPO",
            "model": "CPH1937",
            "networkCarrier": "Jio",
            "os": "Android",
            "platform": "Android",
            "timezone": "Asia/Kolkata",
            "version": "10"
          }
        },
        {
          "browserObject": {
            "deviceType": "mobile",
            "osName": "Android",
            "browserName": "Chrome",
            "osVersion": 10,
            "browserVersion": "80.0.3987.99"
          }
        }
      ]
    }
  },
  "upsert": {}
}

Error is:

{
  "error": {
    "root_cause": [
      {
        "type": "remote_transport_exception",
        "reason": "[connecto][192.168.36.235:9300][indices:data/write/update[s]]"
      }
    ],
    "type": "illegal_argument_exception",
    "reason": "failed to execute script",
    "caused_by": {
      "type": "script_exception",
      "reason": "runtime error",
      "script_stack": [
        "if (params.iterate[index].browserObject) {int ",
        "                         ^---- HERE"
      ],
      "script": "int getBrowsersObjectIndex(def x, def y){for (int i = 0; i < x.length; i++) {if (x[i].deviceType == y.deviceType) {if (x[i].osName == y.osName) {if(x[i].browserName == y.browserName) {return i}}}}return -1} int getDevicesObjectIndex(def x, def y){for (int i = 0; i < x.length; i++) {if (x[i].deviceId == y.deviceId) {if (x[i].appName == y.appName) {if (x[i].appNameSpace == y.appNameSpace){return i}}}}return -1}if (!ctx._source.containsKey('browsers')) {ctx._source['browsers'] = []}if (!ctx._source.containsKey('devices')) {ctx._source['devices'] = []}for (int index = 0; index < params.iterate.length; index++) {if (params.iterate[index].browserObject) {int browserIndex = getBrowsersObjectIndex(ctx._source.browsers, params.iterate[index].browserObject);if (browserIndex >= 0) {ctx._source.browsers.remove(browserIndex);}ctx._source.browsers.add(params.iterate[index].browserObject);}if (params.iterate[index].deviceObject) {int deviceIndex = getDevicesObjectIndex(ctx._source.devices, params.iterate[index].deviceObject);if (deviceIndex >= 0) {ctx._source.devices.remove(deviceIndex);}ctx._source.devices.add(params.iterate[index].deviceObject);}}",
      "lang": "painless",
      "caused_by": {
        "type": "null_pointer_exception",
        "reason": null
      }
    }
  },
  "status": 400
}

Seems like the error is in the if statement where I am checking if either of browserObject or deviceObject exists inside the iterate array of objects.


Solution

  • You need to perform an explicit null-check, i.e.

    if (params.iterate[index].browserObject != null)
    

    Besides, in Kibana Dev Tools, you can use triple quotes """ to properly format your code so it's more legible and easier to read/maintain:

    POST test_script/_update/1
    {
      "scripted_upsert": true,
      "script": {
        "lang": "painless",
        "source": """
        int getBrowsersObjectIndex(def x, def y){
          for (int i = 0; i < x.length; i++) {
            if (x[i].deviceType == y.deviceType) {
              if (x[i].osName == y.osName) {
                if(x[i].browserName == y.browserName) {
                  return i
                }
              }
            }
          }
          return -1
        }
        int getDevicesObjectIndex(def x, def y){
          for (int i = 0; i < x.length; i++) {
            if (x[i].deviceId == y.deviceId) {
              if (x[i].appName == y.appName) {
                if (x[i].appNameSpace == y.appNameSpace){
                  return i
                }
              }
            }
          }
          return -1
        }
        if (!ctx._source.containsKey('browsers')) {
          ctx._source['browsers'] = []
        }
        if (!ctx._source.containsKey('devices')) {
          ctx._source['devices'] = []
        }
        for (int index = 0; index < params.iterate.length; index++) {
          if (params.iterate[index].browserObject != null) {
            int browserIndex = getBrowsersObjectIndex(ctx._source.browsers, params.iterate[index].browserObject);
            if (browserIndex >= 0) {
              ctx._source.browsers.remove(browserIndex);
            }
            ctx._source.browsers.add(params.iterate[index].browserObject);
          }
          if (params.iterate[index].deviceObject != null) {
            int deviceIndex = getDevicesObjectIndex(ctx._source.devices, params.iterate[index].deviceObject);
            if (deviceIndex >= 0) {
              ctx._source.devices.remove(deviceIndex);
            }
            ctx._source.devices.add(params.iterate[index].deviceObject);
          }
        }
        """,
        "params": {
          "iterate": [
            {
              "deviceObject": {
                "deviceId": "162c04e48832e338",
                "appName": "test_app",
                "appNameSpace": "com.test",
                "appBuild": 55,
                "appVersion": "4.6.3",
                "deviceName": "OP4B80L1",
                "manufacturer": "OPPO",
                "model": "CPH1937",
                "networkCarrier": "Jio",
                "os": "Android",
                "platform": "Android",
                "timezone": "Asia/Kolkata",
                "version": "10"
              }
            },
            {
              "browserObject": {
                "deviceType": "mobile",
                "osName": "Android",
                "browserName": "Chrome",
                "osVersion": 10,
                "browserVersion": "80.0.3987.99"
              }
            }
          ]
        }
      },
      "upsert": {}
    }