I have a creeping suspicion that there is something very wrong with me putting a scripted metric inside a filter aggregation inside a terms aggregation.
Here is an example of the type of query that's giving me weird behavior.
{
  "size": 0,
  "aggs": {
    "a": {
      "terms": {
        "field": "id",
        "size": 10
      },
      "aggs": {
        "measure" : {
          "filter" : {
            "bool" : {
              "must" : [
                {
                  "terms" : {
                    "foo.bar" : [
                      "foo"
                    ],
                    "boost" : 1.0
                  }
                },
                {
                  "terms" : {
                    "foo.baz" : [
                      "bar"
                    ],
                    "boost" : 1.0
                  }
                }
              ]
            }
          },
          "aggregations" : {
           "profit": {
      "scripted_metric": {
                "init_script" : "params._agg.transactions = []",
                "map_script" : "params._agg.transactions.add(1)", 
                "combine_script" : "double profit = 0; for (t in params._agg.transactions) { profit += t } return profit",
                "reduce_script" : "double profit = 0; for (a in params._aggs) { profit += a } return profit"
            }
    }
          }
        }
      }
    }
  }
}
At first glance nothing wrong here. Not super complicated its just the example scripted metric inside a filter aggregation inside a terms aggregation.
But the script will through a null pointer in the reduce script!
"caused_by": {
      "type": "script_exception",
      "reason": "runtime error",
      "script_stack": [
        "profit += a } ",
        "^---- HERE"
      ],
      "script": "double profit = 0; for (a in params._aggs) { profit += a } return profit",
      "lang": "painless",
      "caused_by": {
        "type": "null_pointer_exception",
        "reason": null
      }
    }
When debugging this it looks like the reduce script is running TWICE!
If I change the reduce_script to
"reduce_script" : "Debug.explain(params._aggs)" 
I get back
      "to_string": "[null]",
      "java_class": "java.util.ArrayList",
      "script_stack": [
        "Debug.explain(params._aggs); double ",
        "                    ^---- HERE"
      ]
Whats even more crazy is that if I change the reduce script to
"reduce_script" : "if (params._aggs[0] != null) {Debug.explain(params._aggs)}"
I get
"to_string": "[0.0]",
      "java_class": "java.util.ArrayList",
      "script_stack": [
        "Debug.explain(params._aggs)}",
        "                    ^---- HERE"
      ],
      "script": "if (params._aggs[0] != null) {Debug.explain(params._aggs)}",
What's going on here? Why do I get two different values? And why is the script returning a [null] in the first place?