Using ledger.listKnownParties returns Unhandled Promise Rejection Warning

Hi all,

I am new to the daml language and I am attempting to connect to my ledger (running on sandbox with SDK 1.10.0) with JavaScript @daml/ledger JSON API implementation. When I try to use Ledger.listKnownParties it returns an error “UnhandledPromiseRejectionWarning”, as such:

import Ledger from  '@daml/ledger';
import { Choice, ContractId, List, Party, Template, Text } from '@daml/types';

var authToken = {token, httpBaseUrl, wsBaseUrl, reconnectThreshold};
var testLedger = new Ledger(authToken)
var knownParties = testLedger.listKnownParties();

console.log(knownParties)

The error returned on the node is:

    Promise { <pending> }
    (node:48605) UnhandledPromiseRejectionWarning: FetchError: request to http://localhost:6865/v1/parties failed, reason: Parse Error: Expected HTTP/
        at ClientRequest.<anonymous> (/home/vscode/.cache/bazel/_bazel_vscode/192ca8f40b52bc51e3a48d2e2cf17a2d/execroot/project/node_modules/node-fetch/lib/index.js:1461:11)
        at ClientRequest.emit (events.js:210:5)
        at Socket.socketOnData (_http_client.js:463:9)
        at Socket.emit (events.js:210:5)
        at addChunk (_stream_readable.js:308:12)
        at readableAddChunk (_stream_readable.js:289:11)
        at Socket.Readable.push (_stream_readable.js:223:10)
        at TCP.onStreamRead (internal/stream_base_commons.js:182:23)
    (node:48605) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
    (node:48605) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

On the ledger on the other hand I get:

    io.grpc.netty.NettyServerTransport notifyTerminated
    INFO: Transport failed
    io.netty.handler.codec.http2.Http2Exception: Unexpected HTTP/1.x request: GET /v1/parties 
            at io.netty.handler.codec.http2.Http2Exception.connectionError(Http2Exception.java:108)
            at io.netty.handler.codec.http2.Http2ConnectionHandler$PrefaceDecoder.readClientPrefaceString(Http2ConnectionHandler.java:302)
            at io.netty.handler.codec.http2.Http2ConnectionHandler$PrefaceDecoder.decode(Http2ConnectionHandler.java:239)
            at io.netty.handler.codec.http2.Http2ConnectionHandler.decode(Http2ConnectionHandler.java:438)
            at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:508)
            at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:447)
            at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276)
            at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
            at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
            at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
            at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
            at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
            at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
            at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
            at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
            at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719)
            at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655)
            at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581)
            at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
            at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
            at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
            at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
            at java.base/java.lang.Thread.run(Thread.java:832)

I also tried to use CURL to reach the ledger - it returns the same error: Unexpected HTTP/1.x request: GET /v1/parties. I do know it runs, as daml ledger list-parties does return the results.

I tried it with and without authentication enabled on the ledger as well.

I am not sure how to solve this.

2 Likes

Hi @alexkosior,
this looks like you setup the JS bindings to connect to the gRPC Ledger API running on port 6865. The JS bindings should connect to the HTTP JSON API instead which is running on port 7500 by default. By default the port is selected to be the same as window.location in your browser which works if you have a reverse proxy like webpack-dev-server during development or nginx in production that hosts your frontend on the same port as the JSON API. If they run on a different port or you run outside of a browser, you can set the httpBaseUrl field when constructing DamlLedger to the host and port the JSON API is running on.

2 Likes

As for the warning, it’s because testLedger.listKnownParties() returns a Promise, which you then need to handle with the .then(...) or .catch(...) methods.

If you’re not familiar with promises, there are plenty of tutorials online. I wrote one myself.

To handle the promise rejection, you might want to do something like this:

testLedger.listKnownParties()
  .then(knownParties => {
    console.log("Known parties:", knownParties);
    // Do something with `knownParties`.
  })
  .catch(error => {
    console.error(error);
    // Notify the user somehow.
  })

The original concept of promises was that you could have a rejected promise sitting around for some time before attaching a catch handler to it. For example, Firefox used to warn of uncaught rejection errors only when a rejected promise with no rejection handler was garbage collected from memory.

Somebody decided that JavaScript programmers couldn’t be trusted with managing promise rejections properly and changed the HTML spec to require browsers to throw “unhandled promise rejection” errors if a rejected promise has no rejection handlers added before code returns to the event loop.

On a case by case basis you can prevent the host being notified by adding a rejection handler that is never used. The reasoning is that adding a dummy rejection handler to a promise means that should it be rejected it has a rejection handler already - or if it was rejected the host is notified the promise now has a rejection handler - and you can call then and catch multiple times on the same promise.

A nice way to wait for several Promises to resolve to use the Promise.all function. It expects an Array of Promises, and produces a Promise that resolves to an Array containing the values that the individual Promises resolved to. Furthermore, it only resolves after the last Promise resolves. If any of its input Promises rejects, then the entire Promise.all expression rejects as well. It effectively “runs” all of its input processes “at the same time”, emulating the classic “fork-join” pattern.