Skip to main content

Troubleshooting

Common issues when managing DIDs in ISBE and their solutions.

Errors during DID Onboarding

400 Bad Request when calling insertFirstDidDocument

Possible causes:

  • proof does not match did + publicKey — Regenerate the DID/PublicKey/Proof triplet with ./did-gen did -p ... to ensure consistency.
  • vMethodId with incorrect format — Must be 32 bytes in base64url without padding (exact 43 characters). The JWK thumbprint meets this format by default.
  • publicKey with wrong prefix — For secp256k1, it must start with 0x04 (uncompressed format).
  • modelDeploy of the DID does not match the network — If you call the PRO API with a did:isbe:uc-pre:... DID, the operation fails. Ensure match among all three values: network, DID, and API.

The transaction is sent but the DID does not appear

  • Review the status field of the receipt. If it is 0, the transaction was executed but the smart contract reverted. Typical causes:
    • The from EOA does not have authorization to call insertFirstDidDocument (that operation has special authorization).
    • The DID already exists.
  • If status is 1 but the GET still returns 404, wait a few seconds for the indexer to reflect the new block.

Signing Errors

cli-tx-save throws a JSON error when passing the body

If you are using the internal cli-tx-save binary, the -t parameter expects a JSON string inside single quotes. If the JSON contains internal double quotes and you pass it in double quotes, it breaks. Solution:

./sign-tx sign -p 0x<KEY> -t '{"to":"0x...","data":"0x..."}'

If it still gives you trouble, the most portable alternative is to sign with ethers.js or eth_account directly (see Registration via API — step 4).

ethers.js throws "from must be undefined or match the signer"

The POST /contract/... endpoints return from inside the object. ethers refuses to serialize a transaction with a from different from the signer. Solution: discard it before building the Transaction:

const tx = Transaction.from({ ...raw, from: undefined });

eth_account complains about hexadecimal fields

Unlike ethers, eth_account expects native integers in gas, gasPrice, nonce, value, and chainId. Convert the hex 0x... with int(x, 16) before signing.

The signed transaction is rejected with nonce too low

The nonce returned by the API is the EOA's current nonce. If you sent another transaction between generating and signing this transaction, the nonce may have become obsolete. Solution: call the endpoint again to regenerate the transaction.

Errors when Adding Verification Methods

The key does not appear as assertionMethod

Remember that the API exposes the steps separately:

  1. addVerificationMethod registers the key.
  2. addVerificationRelationship associates it with the use (assertionMethod, authentication, etc.).

If you only execute the first one, the key exists but is not usable for signing credentials.

publicKeyType and publicKey format misaligned

publicKeyType determines the format of the publicKey field, not the curve. The curve comes from the registered material itself:

  • publicKeyType: "secp256k1"publicKey must be 64 XY hexadecimal bytes (uncompressed format without JWK wrapper). If you paste a serialized JWK here, the API responds with 400 due to invalid format.
  • publicKeyType: "JsonWebKey2020"publicKey must be a valid JWK serialized to a JSON string and encoded in hex. The actual curve is read from the crv field inside the JWK. It accepts secp256k1, P-256, etc.

Common errors:

  • publicKeyType: "secp256k1" with a serialized JWK in publicKey400 BAD_REQUEST. Input the JWK with publicKeyType: "JsonWebKey2020", or extract the 64 XY bytes of the secp256k1 key and send them as pure hex.
  • publicKeyType: "P-256" literal → 400 UNSUPPORTED with the message "The 'P-256' publicKeyType is temporarily unsupported." The value is reserved in the spec but disabled in the current implementation; use JsonWebKey2020 with crv: "P-256" instead.
  • publicKeyType: "JsonWebKey2020" with a JWK whose crv is not supported by the contract → the insertion may pass format validation, but the key will not be operational for signing. The curves proven to be functional are secp256k1 and P-256.

Confusion with the from EOA

from must always be the EOA of the control secp256k1 key of the DID, not the EOA derived from the new P-256 key. The P-256 is used for off-chain signing; on-chain transactions are signed by the secp256k1.

Resolution Errors

404 Not Found

  • The DID is not registered in that environment (check the modelDeploy).
  • The DID is incorrectly URL-encoded. Some HTTP clients require encoding the : of the DID. Try with cURL first to discard.

406 Not Acceptable

The Accept header is not one of the supported ones:

  • application/did+ld+json
  • application/did+json

Funds / Gas Errors

insufficient funds for gas

The EOA has no balance. In PRE, you can request funds in the Faucet section of the portal. In PRO, funds are assigned in the initial onboarding; contact ISBE if you need more.

gas required exceeds allowance

The gasLimit returned by the API should be sufficient. If you encounter this error, do not modify the gasLimit manually: regenerate the transaction so that the API recalculates it.

Trust Chain Errors

The CLI says that the accreditation is invalid

Common causes:

  • accreditedFor and accreditedSchemas do not have the same cardinality. There must be a 1:1 correlation.
  • The types / schemas are not a subset of those accredited by the parent accreditation.
  • The domain does not match that of the parent accreditation.
  • The URL in accreditedBy is not accessible or returns an invalid JWT.

The verifier cannot find my accreditation

  • Confirm with ISBE that the accreditation has been published in the TIR.
  • Verify that the verifier points to the TIR of the correct environment.

Asking for Help

If you still have problems after reviewing these points, open an issue in the ISBE support portal attaching:

  • Environment (PRE / PRO).
  • Affected DID.
  • Endpoint and request body.
  • Complete response (including tx_hash if the transaction was sent).
  • CLI logs if the issue is local.