JavaScript ポリシーの実行時エラーの解決方法

ScriptExecutionFailed

エラーコード

steps.javascript.ScriptExecutionFailed
    

エラー レスポンスの本文

    {
        "fault": {
            "faultstring": "Execution of javascript_policy_name failed with error: error_type: error_description. (javascript_source_file_name)\"",
            "detail": {
                "errorcode": "steps.javascript.ScriptExecutionFailed"
            }
        }
    }
    

エラーの種類と考えられる原因

JavaScript ポリシーは、さまざまな種類の ScriptExecutionFailed エラーをスローします。その中でもより一般的に遭遇するエラーを以下の表に示します。

エラーの種類 原因
Range Error RangeError は、有効な範囲を外れた数値が使われるとスローされます。
Reference Error ReferenceError は、宣言されていない変数が使用(参照)されるとスローされます。
Syntax Error SyntaxError は、構文エラーのあるコードを評価しようとするとスローされます。
Type Error TypeError は、なんらかの操作をそれが期待する型以外に使うとスローされます。
URI Error URIError は、URI 関数で不正な文字を使用するとスローされます。

Range error

エラータイプ RangeError は、許される範囲や集合以外の値を、操作したり関数に渡したりしたときにスローされます。

たとえば以下のような状況でスローされます。

  1. 2018 年 9 月 31 日といった無効な日付を、一部の Date API で使った場合。
  2. Number.toPrecision()Number.tofixed()Number.toExponential() などの数値メソッドに不正な値を渡した場合。たとえば、Number.toPrecision() メソッドに、400 や 500 といった大きな値を渡したとき、range error が発生します。
  3. 不正な長さで配列を作成したとき。

エラー レスポンスの本文

    {
        "fault": {
            "faultstring": "Execution of javascript_policy_name failed with error: Javascript runtime error: \"RangeError: error_description. (javascript_source_file_name:line_number)\"",
            "detail": {
                "errorcode": "steps.javascript.ScriptExecutionFailed"
            }
        }
    }
    

注: range error の診断と解決は、JavaScript ポリシーがスローしたエラー メッセージが正確にはどのようなものかによって異なります。参考のため、いくつか例を挙げて説明します。

例 1: 無効な日付

エラー レスポンスの本文の例

{
        "fault": {
            "faultstring": "Execution of ParseDate failed with error: Javascript runtime error: \"RangeError: Date is invalid. (ParseDate.js:2)\"",
            "detail": {
                "errorcode": "steps.javascript.ScriptExecutionFailed"
            }
        }
    }
    

診断

  1. JavaScript ポリシー、そのソースファイル、エラーが発生した行番号、エラーの説明を特定します。これらすべての情報はエラー レスポンスの faultstring 要素にあります。たとえば、次の faultstring では、JavaScript ポリシーの名前が ParseDate、JavaScript ソースファイルが ParseDate.js、エラーの発生した行番号が 2、エラーの説明が Date is invalid となります。

    "faultstring": "Execution of ParseDate failed with error: Javascript runtime error: \"RangeError: Date is invalid. (ParseDate.js:2)\""
        
  2. 上のステップ 1 で特定した JavaScript ソースファイルを調べ、エラーに書かれた行番号で、無効な日付が使われていないか、あるいは無効な日付の入った変数が使われていないかを確認します。無効な日付が使われていれば、それがエラーの原因です。

    このエラーを引き起こすサンプル JavaScript ソースファイルを次に示します。

    ParseDate.js

    var date = new Date('2018-09-31T11:19:08.402Z');
        date.toISOString();
        

    上の例では、2 行目で変数 date が使われています。ソースを確認すると、date 変数に無効な日付 2018-09-31T11:19:08.402Z. が設定されていることがわかります。9 月に 31 日はないので、この日付は無効です。

    注: この例で使っている ISO-8601 形式は、YYYY-MM-DDTHH:mm:ss.sssZ です。

解決策

JavaScript コードで Date API を使うときは、必ず有効な日付を使うようにします。

上記のサンプル JavaScript コードを修正するには、次のように日付を Sept 30 2018 に設定します。

var date = new Date('2018-09-30T11:19:08.402Z');
    date.toISOString();
    

例 2: Precision API に不正な数値を渡した

エラー レスポンスの本文の例

{
        "fault": {
            "faultstring": "Execution of SetNumberPrecision failed with error: Javascript runtime error: "RangeError: Precision 400 out of range. (SetNumberPrecision.js:2)\"",
            "detail": {
                "errorcode": "steps.javascript.ScriptExecutionFailed"
            }
        }
    }
    

診断

  1. JavaScript ポリシー、そのソースファイル、エラーが発生した行番号、エラーの説明を特定します。これらすべての情報はエラー レスポンスの faultstring 要素にあります。たとえば、次の faultstring では、JavaScript ポリシーの名前が SetNumberPrecision、JavaScript ソースファイルが SetNumberPrecision.js、エラーの発生した行番号が 2、エラーの説明が Precision 400 out of range. となります。

    "faultstring": "Execution of SetNumberPrecision failed with error: Javascript runtime error: "RangeError: Precision 400 out of range. (SetNumberPrecision.js:2)\""
        
  2. 上のステップ 1 で特定した JavaScript ソースファイルを調べます。エラーの説明に書かれた大きな数値が、エラーに書かれた行番号で使われていれば、それがエラーの原因です。

    このエラーを引き起こすサンプル JavaScript ソースファイルを次に示します。

    SetNumberPrecision.js

    var number = 12.3456;
        var rounded_number = number.toPrecision(400);
        print("rounded_number = " + rounded_number);
        

    上の例では、2 行目で 400 という大きな値が使われています。このような大きな桁数の有効数字は設定できないため、次のエラーがスローされます。

    "faultstring": "Execution of SetNumberPrecision failed with error: Javascript runtime error: "RangeError: Precision 400 out of range. (SetNumberPrecision.js:2)\""
        

解決策

toPrecision() メソッドで使われている数値が、必ず許可された値の範囲内になるようにします。

上のサンプル JavaScript の問題を解決するには、次のように有効数字の桁数を不正でない 2 に設定します。

var number = 12.3456;
    var rounded_number = number.toPrecision(2);
    print("rounded_number = " + rounded_number);
    

Reference error

エラータイプ ReferenceError は、JavaScript で未定義の変数が使用(参照)または操作されたときにスローされます。

エラー レスポンスの本文

    {
        "fault": {
            "faultstring": "Execution of javascript_policy_name failed with error: Javascript runtime error: \"ReferenceError: variable_name is not defined. (javascript_source_file_name:line_number)\"",
            "detail": {
                "errorcode": "steps.javascript.ScriptExecutionFailed"
            }
        }
    }
    

エラー レスポンスの本文の例

{
        "fault": {
            "faultstring": "Execution of ComputeTotalPrice failed with error: Javascript runtime error: \"ReferenceError: \"price\" is not defined. (ComputeTotalPrice.js:3)\"",
            "detail": {
                "errorcode": "steps.javascript.ScriptExecutionFailed"
            }
        }
    }
    

診断

  1. JavaScript ポリシー、そのソースファイル、未定義の変数が参照された行番号を特定します。これらすべての情報はエラー レスポンスの faultstring 要素にあります。たとえば、次の faultstring では、JavaScript ポリシーの名前が ComputeTotalPrice、対応する JavaScript ソースファイルが ComputeTotalPrice.js、エラーの発生した行番号が 3、未定義の変数の名前が price. となります。

    "faultstring": "Execution of ComputeTotalPrice failed with error: Javascript runtime error: \"ReferenceError: \"price\" is not defined. (ComputeTotalPrice.js:3)\""
        
  2. JavaScript ソースファイルでの行番号を調べ、上のステップ 1 で特定した未定義の変数が参照されていないか確認します。たとえば、次の JavaScript コードは、3 行目の未定義の変数 price を参照しています。これは、faultstring の内容と一致します。

    ComputeTotalPrice.js

    var item = context.getVariable("request.queryparam.item");
        var quantity = context.getVariable("request.queryparam.quantity");
        var totalprice = parseInt(quantity) * parseInt(price);
        context.setVariable("TotalPrice", totalprice);
    
        
  3. エラーに書かれた変数が JavaScript コードで定義されているか確認します。その変数が定義されていない場合、それがエラーの原因です。

    上記のサンプル スクリプトでは、宣言 / 定義されていない変数 price が使われています。このため、以下のエラーが発生します。

    "faultstring": "Execution of ComputeTotalPrice failed with error: Javascript runtime error: \"ReferenceError: \"price\" is not defined. (ComputeTotalPrice.js:3)\""
        

解決策

JavaScript コードで参照されるすべての変数は、必ず正しく定義するようにします。

上記のサンプル JavaScript の問題を解決するには、変数 price を使用する前に定義します。例:

var item = context.getVariable("request.queryparam.item");
    var quantity = context.getVariable("request.queryparam.quantity");
    var price = context.getVariable("request.queryparam.price");
    var totalprice = parseInt(quantity) * parseInt(price);
    context.setVariable("TotalPrice", totalprice);
    

Syntax error

エラータイプ SyntaxError は、JavaScript エンジンがこの言語の構文に準拠しないトークンや準拠しないトークンの順序に遭遇した場合、あるいは JSON / XML の構文解析などの構文解析 API に不正な形式の入力があった場合にスローされます。

たとえば、無効あるいは不正な形式の JSON ペイロードが、JavaScript ポリシーの中で使用される JSON.parse API の入力として渡されると、このエラーが発生します。

エラー レスポンスの本文

    {
        "fault": {
            "faultstring": "Execution of javascript_policy_name failed with error: Javascript runtime error: \"SyntaxError: error_description. (javascript_source_file_name:line_number)\"",
            "detail": {
                "errorcode": "steps.javascript.ScriptExecutionFailed"
            }
        }
    }
    

エラー レスポンスの本文の例

{
        "fault": {
            "faultstring": "Execution of ParseJSONRequest failed with error: Javascript runtime error: \"SyntaxError: Unexpected token: <. (ParseJSONRequest.js:2)\"",
            "detail": {
                "errorcode": "steps.javascript.ScriptExecutionFailed"
            }
        }
    }
    

診断

  1. JavaScript ポリシー、そのソースファイル、エラーが発生した行番号、エラーの説明を特定します。これらすべての情報はエラー レスポンスの faultstring 要素にあります。たとえば、次の faultstring では、JavaScript ポリシーの名前が ParseJSONRequest、JavaScript ソースファイルが ParseJSONRequest.js、エラーの発生した行番号が 2、エラーの説明が Unexpected token となります。

    "faultstring": "Execution of ParseJSONRequest failed with error: Javascript runtime error: \"SyntaxError: Unexpected token: <. (ParseJSONRequest.js:2)\""
        
  2. 上のステップ 1 で特定した JavaScript ソースファイルの 2 行目を調べ、実行されているか操作を確認します。JSON.parse() 関数が実行されている場合、それに渡している入力パラメータを確認します。入力パラメータが無効あるいは不正な形式の JSON の場合、それがエラーの原因です。

    このエラーを発生されるサンプル JavaScript コードを次に示します。

    var input = context.getVariable("request.content");
        var result = JSON.parse(input);
        

    上の例では、API プロキシに渡すリクエスト ペイロード(request.content)が、JSON.parse() 関数の入力として使われます。

    次のサンプルの API 呼び出しは、リクエストがどのように渡されたかを示します。

    curl -v "http://<org>-<env>.apigee.net/v1/js-demo" -H "Content-Type: application/json" -X POST -d '<city>Bangalore</city>'
        

    上のリクエストでは、XML ペイロード <city>Bangalore</city> が API プロキシに渡されます。JSON.parse API は有効な JSON が渡されると期待していますが、代わりに XML ペイロードが渡されるため、次のエラーが発生します。

    "Execution of ParseJSONRequest failed with error: Javascript runtime error: \"SyntaxError: Unexpected token: <. (ParseJSONRequest.js:2)\""
        

解決策

JavaScript コードで使われている構文解析 API には必ず有効な入力を渡すようにします。

上記のサンプル ポリシーの問題を解決するには、次のように有効な JSON ペイロードを渡します。

curl -v "http://<org>-<env>.apigee.net/v1/js-demo" -H "Content-Type: application/json" -X POST -d '{"city" : "Bangalore"}'
    

Type error

エラータイプ TypeError は、以下の場合にスローされます。

  • 演算子や関数に渡される被演算子や引数が、期待されるタイプと互換性がない場合。
  • null、未定義のオブジェクト、間違ったオブジェクトに対して関数が呼ばれた場合。
  • null、未定義のオブジェクト、間違ったオブジェクトからプロパティにアクセスした場合。

たとえば以下のような場合に type error がスローされます。

  • 数値に対して toUpperCase() 関数を呼び出そうとした場合。toUpperCase() 関数は文字列オブジェクトに対してだけ呼び出せるためです。
  • null あるいは未定義のオブジェクトからプロパティを読み出そうとした場合。

エラー レスポンスの本文

    {
        "fault": {
            "faultstring": "Execution of javascript_policy_name failed with error: Javascript runtime error: \"TypeError: error_description. (javascript_source_file_name:line_number)\"",
            "detail": {
                "errorcode": "steps.javascript.ScriptExecutionFailed"
            }
        }
    }
    

例 1: 間違ったオブジェクトで関数を呼び出す

サポートされていないオブジェクトで関数を呼び出そうとすると、このエラーが発生します。たとえば、数値に対して toUpperCase() 関数を呼び出そうとすると、このエラーが発生します。toUpperCase() 関数は文字列オブジェクトに対してだけ呼び出せるためです。

エラー レスポンスの本文の例

{
        "fault": {
            "faultstring": "Execution of ConvertToUpperCase failed with error: Javascript runtime error: \"TypeError: Cannot find function toUpperCase in object 100. (ConvertToUpperCase.js:2)\"",
            "detail": {
                "errorcode": "steps.javascript.ScriptExecutionFailed"
            }
        }
    }
    

診断

  1. JavaScript ポリシー、そのソースファイル、エラーが発生した行番号、エラーの説明を特定します。これらすべての情報はエラー レスポンスの faultstring 要素にあります。たとえば、次の faultstring では、JavaScript ポリシーの名前が ConvertToUpperCase、ソースファイルが ConvertToUpperCase.js、行番号が 2、エラーの説明が **Cannot find function toUpperCase in object 100. となります。

    "faultstring": "Execution of ConvertToUpperCase failed with error: Javascript runtime error: \"TypeError: Cannot find function toUpperCase in object 100. (ConvertToUpperCase.js:2)\""
        

    エラーの説明では、数値が 100 のオブジェクトに対して、toUpperCase() 関数を呼び出しています。

  2. JavaScript ソースファイルを調べ、上のステップ 1 で特定した 2 行目で、数値が 100 のオブジェクトに対して、関数 toUpperCase() が呼び出されているか確認します。もしそうなら、それがエラーの原因です。

    このエラーを引き起こすサンプル JavaScript ソースファイルを次に示します。

    ConvertToUpperCase.js

    var number = 100;
        var result = number.toUpperCase();
        

    上の JavaScript コードでは、変数 number が値 100 に設定されています。続いて、toUpperCase()( 関数が数値オブジェクトに対して呼び出されています。toUpperCase() 関数は、文字列オブジェクトに対してだけ呼び出せるため、次のようなエラーが発生します。

    "Execution of ConvertToUpperCase failed with error: Javascript runtime error: \"TypeError: Cannot find function toUpperCase in object 100. (ConvertToUpperCase.js:2)\""
        

解決策

toUpperCase() のような関数は、常に正しいオブジェクトに対して使うようにします。

上記の例を修正するには、次のように、文字列変数を作って、文字列に対して toUpperCase() を呼び出すようにします。

var text = "Hello Apigee !";
    var result = text.toUpperCase();
    

例 2: 未定義オブジェクトからプロパティを読み取れない

未定義オブジェクトのプロパティにアクセスしたり、プロバティを読み出そうとしたりすると、このエラーが発生します。たとえば、配列内のオブジェクトからデータにアクセスしようとして、そのオブジェクトが未定義だった場合、このエラーが発生します。以下の詳細な説明をご覧ください。

エラー レスポンスの本文の例

{
        "fault": {
            "faultstring": "Execution of ParseJSONResponse failed with error: Javascript runtime error: \"TypeError: Cannot read property \"length\" from undefined. (ParseJSONResponse.js:7)\"",
            "detail": {
                "errorcode": "steps.javascript.ScriptExecutionFailed"
            }
        }
    }
    

診断

  1. JavaScript ポリシー、そのソースファイル、エラーが発生した行番号、エラーの説明を特定します。これらすべての情報はエラー レスポンスの faultstring 要素にあります。たとえば、次の faultstring では、JavaScript ポリシーの名前が ParseJSONResponse、ソースファイルが ParseJSONResponse.js、行番号が 6、エラーの説明が Cannot read property "length" from undefined となります。

    "faultstring": "Execution of ParseJSONResponse failed with error: Javascript runtime error: \"TypeError: Cannot read property \"length\" from undefined. (ParseJSONResponse.js:6)\""
        

    このエラーは、未定義オブジェクトからプロパティ length を読み取れないことを示しています。

  2. 上のステップ 1 で特定した JavaScript ソースファイルの行を調べ、オブジェクトが有効な値を持つか、あるいは未定義かを確認します。そのオブジェクトがどのように定義されたか、どのようにして得られたかを特定し、なぜオブジェクトが定義されないとわかるかを確定するには、ソースファイル全体を読んで理解する必要があります。そのオブジェクトが確かに未定義であって、そこからプロパティ length を読み出そうとしているなら、それがエラーの原因です。

    この問題を詳細に理解するために、以下の例を見てみましょう。

    1. 次の JSON レスポンスをバックエンド サーバーから受け取ったとします。

      {
              "cars": [
                 { "name":"Toyota", "count": 150 }
                 { "name":"Honda", "count": 100 },
                 { "name":"Ford", "count": 75 }
              ]
          }
          
    2. 次のサンプル JavaScript ソースファイルが、上の JSON レスポンスを解析し、上記のエラーを発生させます。

      ParseJSONResponse.js

      // Get the JSON response
          var jsonData = context.getVariable("response.content");
          print (jsonData);
      
          // Read the cars array
          for (var i = 0; i < jsonData.cars.length; i++)
            {
            print("name = " + jsonData.cars[i].name);
            print("count = " + jsonData.cars[i].count);
            }
          
    3. JavaScript コードを注意深く調べると、2 行目で response.content が(引用符に囲まれた)通常の文字列として読み出されて変数 jsonData に代入されているのがわかります。

    4. jsonData は通常の文字列なので、jsonData から cars にアクセスしようとすると(jsonData.cars)、未定義になります。

    5. 続いて、jsonData.cars(未定義)からプロパティ length を読み出そうとしたとき、次のエラーが発生します。

      "faultstring": "Execution of ParseJSONResponse failed with error: Javascript runtime error: \"TypeError: Cannot read property \"length\" from undefined. (ParseJSONResponse.js:6)\""
          

解決策

適切な JSON API を使って、必ず JSON オブジェクトとして JSON データを読み出すようにします。

上記のサンプル JavaScript を修正するには、response.content オブジェクトに対して JSON.parse() 関数を使い JSON オブジェクトとして取得します。すると、cars 配列にアクセスし、配列に対する繰り返し処理ができるようになります。

// Get the JSON response
    var data = context.getVariable("response.content");
    var jsonData = JSON.parse(data);
    print (jsonData);

    // Read the cars array
    for (var i = 0; i < jsonData.cars.length; i++)
    {
        print("name = " + jsonData.cars[i].name);
        print("count = " + jsonData.cars[i].count);
    }
    

URI Error

エラータイプ URIError は、URI 関数内で不正な文字を使った場合にスローされます。たとえば、decodeURI 関数や decodeURIComponent 関数にパーセント記号を含む URI を渡すと、このエラーが発生します。

エラー レスポンスの本文

    {
        "fault": {
            "faultstring": "Execution of javascript_policy_name failed with error: Javascript runtime error: \"URIError: error_description. (javascript_source_file_name:line_number)\"",
            "detail": {
                "errorcode": "steps.javascript.ScriptExecutionFailed"
            }
        }
    }
    

エラー レスポンスの本文の例

{
        "fault": {
            "faultstring": "Execution of URIDecode failed with error: Javascript runtime error: \"URIError: Malformed URI sequence. (URIDecode.js:2)\"",
            "detail": {
                "errorcode": "steps.javascript.ScriptExecutionFailed"
            }
        }
    }
    

診断

  1. JavaScript ポリシー、そのソースファイル、エラーが発生した行番号、エラーの説明を特定します。これらすべての情報はエラー レスポンスの faultstring 要素にあります。たとえば、次の faultstring では、JavaScript ポリシーの名前が URIDecode</code、JavaScript ソースファイルが URIDecode.js、エラーの発生した行番号が 2、エラーの説明が Malformed URI sequence となります。

    "faultstring": "Execution of URIDecode failed with error: Javascript runtime error: \"URIError: Malformed URI sequence. (URIDecode.js:2)\""
        

    このエラーの説明は、URIDecode.js の 2 行目で不正な形式の URI シーケンスが使われていることを示しています。

  2. JavaScript ソースファイルを調べ、不正な文字を含む引数が渡された URI 関数がないか確認します。もしあるならば、それがエラーの原因です。

    このエラーを発生される JavaScript ソースファイルの例を次に示します。

    URIDecode.js

    var str = "75%-Completed";
        var decoded_str = decodeURIComponent(str);
        context.setVariable("decoded_str", decoded_str);
        

    上のサンプル JavaScript コードでは、decodeURIComponent() に渡された変数 str にパーセント記号があります。これは不正な文字とみなされるので、エラーが発生します。

    "Execution of URIDecode failed with error: Javascript runtime error: \"URIError: Malformed URI sequence. (URIDecode.js:2)\""
        

解決策

URI 関数には、決められた文字、許されている文字以外を渡さないようにします。

上記のサンプル JavaScript の問題を解決するには、パーセント記号をエンコードします。たとえば、次のように %25 とします。

var str = "75%25-Completed";
    var decoded_str = decodeURIComponent(str);
    context.setVariable("decoded_str", decoded_str);