btcpayserver: Unhandled exception in BTCPayMiddleware during invoice creation

Running BTCPayServer v1.0.3.54 via btcpayserver-docker

  1. user created
  2. store created
  3. token created
  4. try to create invoice with https://github.com/btcpayserver/php-bitpay-client package
$storageEngine = new \Bitpay\Storage\FilesystemStorage();
$privateKey    = $storageEngine->load('/tmp/bitpay.pri');
$publicKey     = $storageEngine->load('/tmp/bitpay.pub');
$client        = new \Bitpay\Client\Client();
$adapter       = new \Bitpay\Client\Adapter\CurlAdapter();
$client->setPrivateKey($privateKey);
$client->setPublicKey($publicKey);
$client->setUri('https://btcpay.my.domain/');
$client->setAdapter($adapter);

$token = new \Bitpay\Token();
$token->setToken('my_token');
$client->setToken($token);

$invoice = new \Bitpay\Invoice();

$item = new \Bitpay\Item();
$item
   ->setPrice(1.99);
$invoice->setItem($item);

$invoice->setCurrency(new \Bitpay\Currency('USD'));

$client->createInvoice($invoice);

http request: headers

Content-Type: application/json
X-BitPay-Plugin-Info: BitPay PHP-Client/2.2.20
User-Agent: BitPay PHP-Client/2.2.20 (PHP 7.1.17-0ubuntu0.17.10.1)
X-Accept-Version: 2.0.0
Content-Length: 585
x-identity: my_pub_key
x-signature: my_signature

body

{"price":1.99,"taxIncluded":null,"currency":"USD","posData":null,"notificationURL":null,"transactionSpeed":"medium","fullNotifications":true,"extendedNotifications":false,"notificationEmail":null,"redirectURL":null,"orderID":null,"itemDesc":null,"itemCode":null,"physical":false,"buyerName":"","buyerAddress1":"","buyerAddress2":"","buyerCity":null,"buyerState":null,"buyerZip":null,"buyerCountry":null,"buyerEmail":null,"buyerPhone":null,"buyerNotify":null,"guid":"08b31884-4d96-f539-a8ad-158e9988b4bd","nonce":1550321074.865315,"token":"my_token"}

http response: HTTP/1.1 500 Internal Server Error

error log

crit: PayServer:      Unhandled exception in BTCPayMiddleware
System.NullReferenceException: Object reference not set to an instance of an object.
   at BTCPayServer.Controllers.InvoiceController.CreateInvoiceCore(Invoice invoice, StoreData store, String serverUrl) in /source/Controllers/InvoiceController.cs:line 75
   at BTCPayServer.Controllers.InvoiceControllerAPI.CreateInvoice(Invoice invoice) in /source/Controllers/InvoiceController.API.cs:line 38
   at lambda_method(Closure , Object )
   at Microsoft.Extensions.Internal.ObjectMethodExecutorAwaitable.Awaiter.GetResult()
   at Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at System.Threading.Tasks.ValueTask`1.get_Result()
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeActionMethodAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeNextActionFilterAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
   at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
   at BTCPayServer.Hosting.BTCPayMiddleware.Invoke(HttpContext httpContext) in /source/Hosting/BTCpayMiddleware.cs:line 46
fail: Microsoft.AspNetCore.Server.Kestrel: Connection id "0HLKGCVH6SPTH", Request id "0HLKGCVH6SPTH:00000001": An unhandled exception was thrown by the application.
System.NullReferenceException: Object reference not set to an instance of an object.
   at BTCPayServer.Controllers.InvoiceController.CreateInvoiceCore(Invoice invoice, StoreData store, String serverUrl) in /source/Controllers/InvoiceController.cs:line 75
   at BTCPayServer.Controllers.InvoiceControllerAPI.CreateInvoice(Invoice invoice) in /source/Controllers/InvoiceController.API.cs:line 38
   at lambda_method(Closure , Object )
   at Microsoft.Extensions.Internal.ObjectMethodExecutorAwaitable.Awaiter.GetResult()
   at Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at System.Threading.Tasks.ValueTask`1.get_Result()
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeActionMethodAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeNextActionFilterAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
   at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
   at BTCPayServer.Hosting.BTCPayMiddleware.Invoke(HttpContext httpContext) in /source/Hosting/BTCpayMiddleware.cs:line 46
   at Microsoft.AspNetCore.Cors.Infrastructure.CorsMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 18 (9 by maintainers)

Most upvoted comments

It is a bug on btcpay side, fixing it.

The problem was taxIncluded field. For some reason, json.net accept it not being specified but do not accept null value. I made the field “nullable”. Fixed in 1.0.3.57.

I will try playing with your request above.

Yep there’s still a null reference exception

docker container

9f6e53fd487f    btcpayserver/btcpayserver:1.0.3.55  "dotnet BTCPayServer…"  About a minute ago Up About a minute   49392/tcp generated_btcpayserver_1

running the php script:

% php create_invoice.php
PHP Warning:  array_key_exists() expects parameter 2 to be array, null given in /foo/bar/php-bitpay-client/src/Bitpay/Client/Client.php on line 119
PHP Warning:  array_key_exists() expects parameter 2 to be array, null given in /foo/bar/php-bitpay-client/src/Bitpay/Client/Client.php on line 121
PHP Warning:  array_key_exists() expects parameter 2 to be array, null given in /foo/bar/php-bitpay-client/src/Bitpay/Client/Client.php on line 125
PHP Warning:  array_key_exists() expects parameter 2 to be array, null given in /foo/bar/php-bitpay-client/src/Bitpay/Client/Client.php on line 130
PHP Warning:  array_key_exists() expects parameter 2 to be array, null given in /foo/bar/php-bitpay-client/src/Bitpay/Client/Client.php on line 131
PHP Warning:  array_key_exists() expects parameter 2 to be array, null given in /foo/bar/php-bitpay-client/src/Bitpay/Client/Client.php on line 132
PHP Warning:  array_key_exists() expects parameter 2 to be array, null given in /foo/bar/php-bitpay-client/src/Bitpay/Client/Client.php on line 134
PHP Warning:  array_key_exists() expects parameter 2 to be array, null given in /foo/bar/php-bitpay-client/src/Bitpay/Client/Client.php on line 135
PHP Warning:  array_key_exists() expects parameter 2 to be array, null given in /foo/bar/php-bitpay-client/src/Bitpay/Client/Client.php on line 136
PHP Warning:  array_key_exists() expects parameter 2 to be array, null given in /foo/bar/php-bitpay-client/src/Bitpay/Client/Client.php on line 137
PHP Warning:  array_key_exists() expects parameter 2 to be array, null given in /foo/bar/php-bitpay-client/src/Bitpay/Client/Client.php on line 138
POST https://test.coinpay.host.com/invoices HTTP/1.1
Content-Type: application/json
X-BitPay-Plugin-Info: BitPay PHP-Client/2.2.20
User-Agent: BitPay PHP-Client/2.2.20 (PHP 7.2.15-0ubuntu0.18.04.1)
X-Accept-Version: 2.0.0
Content-Length: 696
x-identity: 02e067134011042fd14b39a9200ec5d816ea7b255e390ba7cf2040a3fb28250c92
x-signature: 3044022075c9e865b6bd6cf98c8d77b6f8c623e6552584deedd6ece028669f161e5104ee02201b4365391c3a6e061dd989477d6c2950194308bd026318ee24867bad392128fb

{"price":1.99,"taxIncluded":null,"currency":"USD","posData":null,"notificationURL":"https:\/\/store.example.com\/bitpay\/callback","transactionSpeed":"medium","fullNotifications":true,"extendedNotifications":false,"notificationEmail":null,"redirectURL":null,"orderID":"OrderIdFromYourSystem","itemDesc":"General Description of Item","itemCode":"skuNumber","physical":false,"buyerName":"","buyerAddress1":"","buyerAddress2":"","buyerCity":null,"buyerState":null,"buyerZip":null,"buyerCountry":null,"buyerEmail":"buyeremail@test.com","buyerPhone":null,"buyerNotify":null,"guid":"504987ff-f6c1-c484-ab22-3043fb5b2999","nonce":1550735251.870323,"token":"9h3yznjGWqVNGSmoKcCGmbaKsNntjKBfbPZNxheDJPBT"}


HTTP/1.1 500 Internal Server Error
Server: nginx
Date: Thu, 21 Feb 2019 07:47:32 GMT
Content-Length: 0
Connection: keep-alive
Strict-Transport-Security: max-age=31536000

btcpayserver exception

fail: Microsoft.AspNetCore.Server.Kestrel: Connection id "0HLKNQ00SQ61V", Request id "0HLKNQ00SQ61V:00000001": An unhandled exception was thrown by the application.
System.NullReferenceException: Object reference not set to an instance of an object.
   at BTCPayServer.Controllers.InvoiceController.CreateInvoiceCore(Invoice invoice, StoreData store, String serverUrl, List`1 additionalTags) in /source/Controllers/InvoiceController.cs:line 81
   at BTCPayServer.Controllers.InvoiceControllerAPI.CreateInvoice(Invoice invoice) in /source/Controllers/InvoiceController.API.cs:line 37
   at lambda_method(Closure , Object )
   at Microsoft.Extensions.Internal.ObjectMethodExecutorAwaitable.Awaiter.GetResult()
   at Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at System.Threading.Tasks.ValueTask`1.get_Result()
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeActionMethodAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeNextActionFilterAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
   at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
   at BTCPayServer.Hosting.BTCPayMiddleware.Invoke(HttpContext httpContext) in /source/Hosting/BTCpayMiddleware.cs:line 57
   at Microsoft.AspNetCore.Cors.Infrastructure.CorsMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)

Yesterday after doing some research tests with the python client alongside the php one and sniffing the HTTP traffic using Wireshark I saw that the difference between the requests is in the body of the json data being sent. The python client sends only the fields that are not specifically set to null while the php version sends out a whole body of json object properties which are set to null.

btcpayserver could be checking object properties only instead of also checking if they’re null.

what could be done is this:

  1. stop sending default null values from the php client
  2. check if an invoice property has a null value before using it in btcpayserver. i really hate reading c# code and all the likes of it so i didn’t really get to follow the flow in there.

Should be fixed by 126fbdfd60bd6dedb2c7d2cac2a9aa7d3075f89b will release new version shortly