Ledger API gRPC error code

Is the gPRC error code ledger agnostic? We are trying to put up a error code list for command submission/completion. Can anyone help us to check if there is anything missing or incorrect?

Submission Service Status Completion Service Status Recommendation
OK OK All good, command completed
OK ABORTED Command failed and no transaction committed
OK INVALID_ARGUMENT Depends on the scenario, e.g. Duplicated Contract Key
ALREADY_EXIST n/a The command has been submitted. Wait for the existing command to complete
INVALID_ARGUMENT n/a Depends on the scenario,
e.g. Cannot find key to fetch;
Unable to form consensus (error message starting with Disputed or Inconsistent)
INTERNAL; UNKNOWN; UNAVAILABLE n/a Network related error
ABORTED; DEADLINE_EXCEEDED n/a time out, no response
NOT_FOUND n/a incorrect ledger id is used
RESOURCE_EXHAUSTED n/a system is busy, wait and then retry
UNAUTHENTICATED n/a if the request does not include a valid access token
PERMISSION_DENIED n/a if the claims in the token are insufficient to perform a given operation

This text will be hidden


There is a small chapter on error codes in the docs but this is way more complete, I believe this is worth a contribution. :wink:


The Ledger API docs list all the errors a service can return. See for example Active Contract Service. The errors listed there are the ones returned by the Ledger API Server, not technical errors emitted by gRPC like networking issues, but that seems to match your list.

I notice that ALREADY_EXIST isn’t listed, which is something that needs to be fixed (ed. #8569. I’ll add an issue for that. However, some additional ones are listed:

  • UNAUTHENTICATED : if the request does not include a valid access token
  • PERMISSION_DENIED : if the claims in the token are insufficient to perform a given operation

Do we know what error code it will return if the ledger is unable to form consensus? Also is it possible that the command submission returns OK but command completion returns PERMISSION_DENIED?

1 Like

I believe it’s UNKNOWN (Ed: Wrong, it’s actually INVALID_ARGUMENT), with an error message starting with Disputed or Inconsistent. You can test this quite easily because you can cause consensus to fail with contract keys.

template Delegated
    owner : Party
    k : Text
    signatory owner
    key (owner, k) : (Party, Text)
    maintainer key._1

template Delegation
    owner : Party
    delegate : Party
    signatory owner
    observer delegate

    controller delegate can
      nonconsuming Lookup: ()
          p: Party
          k: Text
          lookupByKey @Delegated (p, k)
          return ()

test_error : Script ()
test_error = do
  m <- allocatePartyWithHint "m" (PartyIdHint "m")
  alice <- allocatePartyWithHint "Alice" (PartyIdHint "Alice")

  delegated <- submit m do
    createCmd Delegated with
      owner = m
      k = "key"

  delegationCid <- submit m do
    createCmd Delegation with
      owner = m
      delegate = alice

  submit alice do
    exerciseCmd delegationCid Lookup with
      p = m
      k = "key"

  return ()

Start a sandbox with

daml start --sandbox-option="--ledgerid=x"

Start listening for completions using grpcurl:

grpcurl -plaintext -d '{"application_id": "script", "ledgerId" : "x", "parties": ["Alice"] }' localhost:6865 com.daml.ledger.api.v1.CommandCompletionService.CompletionStream

And finally, run the script:

daml script --dar .daml/dist/key-test-0.0.1.dar --script-name Main:test_error --ledger-host localhost --ledger-port 6865 --application-id="script"

Yes, if you use the command submission service rather than the command service, that is possible. Afaik the command submission service only waits for the Ledger API server to accept the message - ie you’ve sent a valid proto message with a matching token. Interpretation and anything that comes after would only be returned by the completion service.

1 Like

The sandbox and the Daml Driver for PostgreSQL both return INVALID_ARGUMENT in those situations.


:man_facepalming: Off-by-one error on my part. Yes, it’s code 3, which I incorrectly translated to UNKNOWN. Thanks @stefanobaghino-da


Hey @Frankie since you and @zoraizmahmood have been very interested in understanding Daml’s error codes I wanted to give you a heads-up that the DamlLf errors ContractNotFound, and ReplayMismatch have been improved by changing their error code from INVALID_ARGUMENT to ABORTED bringing them more in line with their intended meaning.

Release notes come out for the 1.12.0 RC tomorrow but that’s the gist of the change thus far (and perhaps more in the future per @Andreas_Lochbihler’s comment on the GitHub issue)

1 Like