Getting Empty Contracts from
I’m trying to query active contracts using the HTTP API, but all I am getting back is workflowId’s and empty contractEntry objects. I am on 3.3 and trying to get the active contracts at ledger-end. I am following the docs here: JSON Ledger API Service V2 — Digital Asset’s platform documentation
How do I get the info out of the contractEntry objects, or some reference to the contract?
I am trying to get the contracts like this:
static async listActiveContracts(filters: ContractFilters = {}): Promise<any[]> {
try {
// We are using a single participant atm
const token = await TokenGenerator.generateUserValidatorToken();
const config = new Configuration({
basePath: process.env.USER_PARTICIPANT_URL!,
headers: {
Authorization: `Bearer ${token}`,
},
});
const api = new DefaultApi(config);
const ledgerEnd = await api.getV2StateLedgerEnd();
const request: GetActiveContractsRequest = {
verbose: true,
activeAtOffset: ledgerEnd.offset,
filter: {
filtersByParty: filters.partyId
? {
[filters.partyId]: {
cumulative: [
{
identifierFilter: {
templateFilter: {
value: {
templateId: filters.contractType,
includeCreatedEventBlob: true,
},
},
},
},
],
},
}
: {},
},
};
const response = await api.postV2StateActiveContracts({ getActiveContractsRequest: request });
console.log("Raw response structure:", JSON.stringify(response, null, 2));
const contracts = response.map((r) => r.contractEntry);
return contracts;
} catch (error: unknown) {
console.error("Error listing active contracts:", error);
if (error instanceof Error) {
throw new Error(`Failed to list active contracts: ${error.message}`);
}
throw new Error("Failed to list active contracts: Unknown error");
}
}
The response seems to contain transaction events and empty contractEntry objects:
[
{
"workflowId": "exercise-InvestmentPool_Expire-1760613502733",
"contractEntry": {}
},
{
"workflowId": "exercise-InvestmentPool_Expire-1760613549749",
"contractEntry": {}
},
{
"workflowId": "exercise-InvestmentPool_Archive-1760614505206",
"contractEntry": {}
},
{
"workflowId": "exercise-InvestmentPool_Archive-1760614608198",
"contractEntry": {}
},
{
"workflowId": "exercise-InvestmentPool_Unarchive-1760615662226",
"contractEntry": {}
},
{
"workflowId": "exercise-InvestmentPool_Unarchive-1760615889958",
"contractEntry": {}
},
{
"workflowId": "exercise-InvestmentPool_Archive-1760617507418",
"contractEntry": {}
},
{
"workflowId": "exercise-InvestmentPool_Archive-1760618108291",
"contractEntry": {}
},
{
"workflowId": "exercise-InvestmentPool_GoLive-1760945022994",
"contractEntry": {}
},
{
"workflowId": "create-contract",
"contractEntry": {}
},
{
"workflowId": "create-contract",
"contractEntry": {}
},
{
"workflowId": "create-contract",
"contractEntry": {}
}
]
Decoded token payload: {
exp: 1761113053,
iat: 1761112753,
jti: 'trrtcc:0ba4a47c-23f4-510b-48a2-11246c4082a9',
iss: 'https://keycloak.dserv.io/realms/AppUser',
aud: [ 'https://canton.network.global', 'account' ],
sub: 'c5d77…XXXXX…e1fbb33',
typ: 'Bearer',
azp: 'app-user-validator',
acr: '1',
'allowed-origins': [ '/*' ],
realm_access: {
roles: [ 'offline_access', 'uma_authorization', 'default-roles-appuser' ]
},
resource_access: { account: { roles: [Array] } },
scope: 'profile email',
email_verified: false,
clientHost: '85.230.60.110',
preferred_username: 'service-account-app-user-validator',
clientAddress: '85.230.60.110',
client_id: 'app-user-validator'
}
Here is the result from creating a contract:
{
"transaction": {
"updateId": "1220fe616dd17534f96894e92a8c46176a289c10711ea544a9e19057d60a908c32d9",
"commandId": "create-contract-1761110933730",
"workflowId": "create-contract",
"effectiveAt": "2025-10-22T05:28:54.872955Z",
"events": [
{
"CreatedEvent": {
"offset": 228985,
"nodeId": 0,
"contractId": "00a25eaa50483c6ac26f707a0e2b69f5771b74e99318abd472ed1a2d9b7ab84694ca1112205739f97109dcc8c8ca8645fd65e585a6f79d8a1fa766b79830b7b14a8c533885",
"templateId": "6bb48e1c7f34a2263e0024dc4e9d84ef33bee85ee0974ef46379c7759e9a2125:Dserv.Investment:InvestmentPool",
"contractKey": null,
"createArgument": {
"name": "e42190f9-e6fe-4741-b83f-f0aa62ca233b",
"status": "TOKENIZED",
"provider": "user_tenant12_at_abc123_dot_com::12204045cfaa811009ac22de6f94424284a8fdd20fc54a84cf0a87cb46ac7581dac8",
"numTokensInit": "210000.00",
"numTokensAvailable": "210000.00",
"id": "Loan-2025-10-22T05-28-49-0"
},
"createdEventBlob": "",
"interfaceViews": [],
"witnessParties": [
"user_tenant12_at_abc123_dot_com::12204045cfaa811009ac22de6f94424284a8fdd20fc54a84cf0a87cb46ac7581dac8"
],
"signatories": [
"user_tenant12_at_abc123_dot_com::12204045cfaa811009ac22de6f94424284a8fdd20fc54a84cf0a87cb46ac7581dac8"
],
"observers": [],
"createdAt": "2025-10-22T05:28:54.872955Z",
"packageName": "daml-dserv"
}
}
],
"offset": 228985,
"synchronizerId": "global-domain::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a",
"traceContext": {
"traceparent": "00-b022dc515821f263f84c4de1dca56145-b9090e06de0c57fc-01",
"tracestate": null
},
"recordTime": "2025-10-22T05:28:55.152011Z"
}
}
Thanks all!
This one has me stumped too.
Any chance that request does not have the value we think? Want to JSON.stringify it so that we can double-check it?
Sure, and thank you! I added the line
console.log("Requesting active contracts with:", JSON.stringify(request, null, 2));
const response = await api.postV2StateActiveContracts({ getActiveContractsRequest: request });
console.log("Raw response structure:", JSON.stringify(response, null, 2));
and here is the output:
Decoded token payload: {
exp: 1761149346,
iat: 1761149046,
jti: 'trrtcc:a514ce85-d913-a744-7e6e-69faa628037b',
iss: 'https://keycloak.dserv.io/realms/AppUser',
aud: [ 'https://canton.network.global', 'account' ],
sub: 'c5d7778a-ce31-41e3-9c82-34f03e1fbb33',
typ: 'Bearer',
azp: 'app-user-validator',
acr: '1',
'allowed-origins': [ '/*' ],
realm_access: {
roles: [ 'offline_access', 'uma_authorization', 'default-roles-appuser' ]
},
resource_access: { account: { roles: [Array] } },
scope: 'profile email',
email_verified: false,
clientHost: '85.230.60.110',
preferred_username: 'service-account-app-user-validator',
clientAddress: '85.230.60.110',
client_id: 'app-user-validator'
}
Token verified successfully
Requesting active contracts with: {
"verbose": true,
"activeAtOffset": 232434,
"filter": {
"filtersByParty": {
"user_tenant12_at_abc123_dot_com::12204045cfaa811009ac22de6f94424284a8fdd20fc54a84cf0a87cb46ac7581dac8": {
"cumulative": [
{
"identifierFilter": {
"templateFilter": {
"value": {
"templateId": "#daml-dserv:Dserv.Investment:InvestmentPool",
"includeCreatedEventBlob": true
}
}
}
}
]
}
}
}
}
body {
filter: {
filtersByParty: {
'user_tenant12_at_abc123_dot_com::12204045cfaa811009ac22de6f94424284a8fdd20fc54a84cf0a87cb46ac7581dac8': [Object]
},
filtersForAnyParty: undefined
},
verbose: true,
activeAtOffset: 232434,
eventFormat: undefined
}
Raw response structure: [
{
"workflowId": "exercise-InvestmentPool_Expire-1760613502733",
"contractEntry": {}
},
{
"workflowId": "exercise-InvestmentPool_Expire-1760613549749",
"contractEntry": {}
},
{
"workflowId": "exercise-InvestmentPool_Archive-1760614505206",
"contractEntry": {}
},
{
"workflowId": "exercise-InvestmentPool_Archive-1760614608198",
"contractEntry": {}
},
{
"workflowId": "exercise-InvestmentPool_Unarchive-1760615662226",
"contractEntry": {}
},
{
"workflowId": "exercise-InvestmentPool_Unarchive-1760615889958",
"contractEntry": {}
},
{
"workflowId": "exercise-InvestmentPool_Archive-1760617507418",
"contractEntry": {}
},
{
"workflowId": "exercise-InvestmentPool_Archive-1760618108291",
"contractEntry": {}
},
{
"workflowId": "exercise-InvestmentPool_GoLive-1760945022994",
"contractEntry": {}
},
{
"workflowId": "create-contract",
"contractEntry": {}
},
{
"workflowId": "create-contract",
"contractEntry": {}
},
{
"workflowId": "create-contract",
"contractEntry": {}
}
]
Do you get a different result if you capitalize TemplateFilter?
This may come down to differences in versions.
If I do this…
curl http://localhost:7575/docs/openapi > openapi.yaml
…then I can see that TemplateFilter is expected to be PascalCase. Submitting with TemplateFilter succeeds. Submitting with templateFilter fails:
Invalid value for: body (JSON decoding to CNil should never happen at 'identifierFilter')
I’m using the Splice release 0.4.20. You?
I was on 0.4.18. I updated to 0.4.20 and regenerated the clients but still get the same result.
I can also see PascalCase in the OpenAPI spec but the generated OpenAPI client expects camelCase.
Thank you for upgrading and regenerating the OpenAPI client.
I wonder if the generated OpenAPI client is not deserializing the raw response correctly. It is likely you are receiving back a complete response in the raw. But the contractEntry fields are printed as empty objects. The values on those contractEntry fields are expected to be type JsActiveContract.
[
{
"workflowId": "exercise-InvestmentPool_Expire-1760613502733",
"contractEntry": {}
},
:
:
Is it possible that the auto-generated OpenAPI client is expecting jsActiveContract (lower-case) and ignoring the JsActiveContract (upper-case) in the raw response?
The Open API spec:
JsContractEntry:
title: JsContractEntry
:
oneOf:
- type: object
required:
- JsActiveContract
:
It looks like that was it. Thank you!
Scary stuff!
For those who follow your footsteps, how did you “fix” it? Is there an option available in your OpenAPI-generated client?
I wasn’t able to fix the code generation. I had to modify JsGetActiveContractsResponse to handle both camelCase and PascalCase.
So in JsContractEntryOneOfFromJSONTyped I changed
- return {
'jsActiveContract': JsActiveContractFromJSON(json['JsActiveContract']),- };
to
// Handle both PascalCase and camelCase
const activeContract = json[“JsActiveContract”] || json[“jsActiveContract”];
return {
jsActiveContract: JsActiveContractFromJSON(activeContract),
};}
and in instanceOfJsContractEntryOneOf I changed
if (!('jsActiveContract' in value) || value['jsActiveContract'] === undefined) return false;
to
// Check for both PascalCase and camelCase versions
if (
("JsActiveContract" in value && value["JsActiveContract"] !== undefined) ||
("jsActiveContract" in value && value["jsActiveContract"] !== undefined)
) {
return true;
}
return false;
Here is the entire file:
/* tslint:disable */
/* eslint-disable */
/**
* JSON Ledger API HTTP endpoints
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 3.3.0-SNAPSHOT
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import { mapValues } from "../runtime";
import type { JsActiveContract } from "./JsActiveContract";
import {
JsActiveContractFromJSON,
JsActiveContractFromJSONTyped,
JsActiveContractToJSON,
JsActiveContractToJSONTyped,
} from "./JsActiveContract";
/**
*
* @export
* @interface JsContractEntryOneOf
*/
export interface JsContractEntryOneOf {
/**
*
* @type {JsActiveContract}
* @memberof JsContractEntryOneOf
*/
jsActiveContract: JsActiveContract;
}
/**
* Check if a given object implements the JsContractEntryOneOf interface.
*/
export function instanceOfJsContractEntryOneOf(value: object): value is JsContractEntryOneOf {
// Check for both PascalCase and camelCase versions
if (
("JsActiveContract" in value && value["JsActiveContract"] !== undefined) ||
("jsActiveContract" in value && value["jsActiveContract"] !== undefined)
) {
return true;
}
return false;
}
export function JsContractEntryOneOfFromJSON(json: any): JsContractEntryOneOf {
return JsContractEntryOneOfFromJSONTyped(json, false);
}
export function JsContractEntryOneOfFromJSONTyped(json: any, ignoreDiscriminator: boolean): JsContractEntryOneOf {
if (json == null) {
return json;
}
// Handle both PascalCase and camelCase
const activeContract = json["JsActiveContract"] || json["jsActiveContract"];
return {
jsActiveContract: JsActiveContractFromJSON(activeContract),
};
}
export function JsContractEntryOneOfToJSON(json: any): JsContractEntryOneOf {
return JsContractEntryOneOfToJSONTyped(json, false);
}
export function JsContractEntryOneOfToJSONTyped(
value?: JsContractEntryOneOf | null,
ignoreDiscriminator: boolean = false
): any {
if (value == null) {
return value;
}
return {
JsActiveContract: JsActiveContractToJSON(value["jsActiveContract"]),
};
}
