INTEGRATION TROUBLESHOOTING

Handle Dataverse 204 No Content without a JSON parsing error

Accept an empty successful response, keep its row identity, and test throttling and precondition failures separately.

Provider documentation checked 8 November 2026. Examples below use fixed synthetic fixtures; no request runs from this page.

The create succeeded. Your JSON parser failed.

A connector sends an Account create, receives HTTP 204, then reports an exception because its success handler calls response.json(). There is no JSON document to parse. Treating that parsing exception as a failed create can lead to an unnecessary second write.

Provider contract: Microsoft's basic create example returns 204 with no response body and identifies the new row in OData-EntityId. A successful PATCH update can also return 204; do not require a create identity header on every update.

Requesting Prefer: return=representation is a different contract. Microsoft's create-with-data example returns 201 and JSON, without the create identity header. An empty 204 is not a broken version of that representation response.

Reproduce the empty success on your own receiver

  1. In an existing workspace, install Microsoft Dataverse Accounts API. Select Create Account → Account row created (dataverse-account-created). Keep default fixture mode; no lifecycle is needed.
  2. Copy that installation's receiver URL into your local test configuration. It is the NotTheRealAPI /r/<your-receiver-token> prefix followed by the operation path shown below. Replace the placeholder locally; never paste a private receiver URL into public logs or use real Microsoft credentials.
  3. Send the generated request below. Record the status, response headers and empty body before running your client's deserialisation step.
  4. In the installed module's request inspection, check the captured POST path, synthetic headers and JSON body, then the selected response status. Compare the response headers you received with the example. A 204 must not require a JSON body to pass.

Create Account: Account row created

Documented Synthetic illustrative example from the catalogue, not a live capture. Run only after installing your own receiver. Replace <your-receiver-token> locally; no request is sent from this page.

HTTP 204 · No response body

curl / Bash request

printf '%s' '{"name":"Example Test Co"}' | \
curl -i -X POST \
  'https://nottherealapi.com/r/<your-receiver-token>/api/data/v9.2/accounts' \
  -H 'Authorization: Bearer synthetic-microsoft-dataverse-token' \
  -H 'Accept: application/json' \
  -H 'OData-Version: 4.0' \
  -H 'OData-MaxVersion: 4.0' \
  -H 'Content-Type: application/json' \
  --data-binary @-

PowerShell request

$body = '{"name":"Example Test Co"}'
Invoke-WebRequest `
    -UseBasicParsing `
    -Uri 'https://nottherealapi.com/r/<your-receiver-token>/api/data/v9.2/accounts' `
    -Method POST `
    -Headers @{
    Authorization = 'Bearer synthetic-microsoft-dataverse-token'
    Accept = 'application/json'
    'OData-Version' = '4.0'
    'OData-MaxVersion' = '4.0'
    } `
    -ContentType 'application/json' `
    -Body ([Text.Encoding]::UTF8.GetBytes($body))

Selected synthetic response

HTTP 204
odata-version: 4.0
odata-entityid: https://org.example.test/api/data/v9.2/accounts(00000000-0000-0000-0000-000000000001)

The selected fixture's identity points to org.example.test with a fixed example row ID. It is illustrative: do not follow it expecting a persisted account or replace it with a live tenant URL for this test. HTTP header names are case-insensitive.

Client policy: retain the identity string if your workflow needs it. If an expected header is missing, flag identity as unavailable and diagnose that separately from HTTP success. Do not automatically repeat a create just to obtain its identity.

Assert separate outcomes, not an automatic sequence

Change the operation and behaviour explicitly before each test. The representation fixture is selected separately; adding a Prefer header alone does not switch the simulator. A successful create does not cause a later throttle or ETag conflict.

Selected fixture → client assertion
Operation and behaviourSelected wire outcomeWhat to assert
Create Account: Account row created
dataverse-account-created
HTTP 204 · No response body
Documented
Accept success without calling json(). Read OData-EntityId when supplied; do not invent a response object.
Create Account: Created row representation
dataverse-create-representation
HTTP 201
Documented
Parse the selected JSON representation. Do not require OData-EntityId on this response.
Update Account: Service protection throttling
dataverse-throttle
HTTP 429 · 0x80072321 · Retry-After: 30
Documented
Report failure and apply the supplied Retry-After within a bounded retry/deadline policy. Do not increase concurrency.
Update Account: Concurrent update conflict
dataverse-conflict
HTTP 412 ·
Representative
Report a precondition failure. Reconcile the stale write; do not treat it as a successful update or blindly repeat it.

In real Dataverse, service-protection 429 responses include Retry-After in seconds. Use the actual header when present, cap attempts and total waiting time, and surface exhaustion to the caller. The fixture's wait and remaining-limit values are examples, not your tenant's quota.

Microsoft's optimistic-concurrency update uses If-Match and returns 412 for a stale ETag. Here, the selected 412 is representative: its message and empty error code are fixture values, and changing If-Match does not evaluate a real row version.

Request and response examples for the other selected cases

Create Account: Created row representation

Documented Synthetic illustrative example from the catalogue, not a live capture. Run only after installing your own receiver. Replace <your-receiver-token> locally; no request is sent from this page.

HTTP 201

curl / Bash request

printf '%s' '{"name":"Example Test Co"}' | \
curl -i -X POST \
  'https://nottherealapi.com/r/<your-receiver-token>/api/data/v9.2/accounts' \
  -H 'Authorization: Bearer synthetic-microsoft-dataverse-token' \
  -H 'Accept: application/json' \
  -H 'OData-Version: 4.0' \
  -H 'OData-MaxVersion: 4.0' \
  -H 'Prefer: return=representation' \
  -H 'Content-Type: application/json' \
  --data-binary @-

PowerShell request

$body = '{"name":"Example Test Co"}'
Invoke-WebRequest `
    -UseBasicParsing `
    -Uri 'https://nottherealapi.com/r/<your-receiver-token>/api/data/v9.2/accounts' `
    -Method POST `
    -Headers @{
    Authorization = 'Bearer synthetic-microsoft-dataverse-token'
    Accept = 'application/json'
    'OData-Version' = '4.0'
    'OData-MaxVersion' = '4.0'
    Prefer = 'return=representation'
    } `
    -ContentType 'application/json' `
    -Body ([Text.Encoding]::UTF8.GetBytes($body))

Selected synthetic response

HTTP 201
content-type: application/json
odata-version: 4.0
preference-applied: return=representation

{
  "@odata.context": "https://org.example.test/api/data/v9.2/$metadata#accounts/$entity",
  "@odata.etag": "W/\"536537\"",
  "accountid": "00000000-0000-0000-0000-000000000001",
  "name": "Example Test Co"
}

Update Account: Service protection throttling

Documented Synthetic illustrative example from the catalogue, not a live capture. Run only after installing your own receiver. Replace <your-receiver-token> locally; no request is sent from this page.

HTTP 429 · 0x80072321 · Retry-After: 30

curl / Bash request

printf '%s' '{"name":"Updated Example Co"}' | \
curl -i -X PATCH \
  'https://nottherealapi.com/r/<your-receiver-token>/api/data/v9.2/accounts(00000000-0000-0000-0000-000000000001)' \
  -H 'Authorization: Bearer synthetic-microsoft-dataverse-token' \
  -H 'Accept: application/json' \
  -H 'OData-Version: 4.0' \
  -H 'OData-MaxVersion: 4.0' \
  -H 'If-Match: *' \
  -H 'Content-Type: application/json' \
  --data-binary @-

PowerShell request

$body = '{"name":"Updated Example Co"}'
Invoke-WebRequest `
    -UseBasicParsing `
    -Uri 'https://nottherealapi.com/r/<your-receiver-token>/api/data/v9.2/accounts(00000000-0000-0000-0000-000000000001)' `
    -Method PATCH `
    -Headers @{
    Authorization = 'Bearer synthetic-microsoft-dataverse-token'
    Accept = 'application/json'
    'OData-Version' = '4.0'
    'OData-MaxVersion' = '4.0'
    'If-Match' = '*'
    } `
    -ContentType 'application/json' `
    -Body ([Text.Encoding]::UTF8.GetBytes($body))

Selected synthetic response

HTTP 429
content-type: application/json
retry-after: 30
x-ms-ratelimit-burst-remaining-xrm-requests: 0
x-ms-ratelimit-time-remaining-xrm-requests: 0
odata-version: 4.0

{
  "error": {
    "code": "0x80072321",
    "message": "Service protection API limit exceeded. Decrease request rate and retry later."
  }
}

Update Account: Concurrent update conflict

Representative Synthetic illustrative example from the catalogue, not a live capture. Run only after installing your own receiver. Replace <your-receiver-token> locally; no request is sent from this page.

HTTP 412 ·

curl / Bash request

printf '%s' '{"name":"Updated Example Co"}' | \
curl -i -X PATCH \
  'https://nottherealapi.com/r/<your-receiver-token>/api/data/v9.2/accounts(00000000-0000-0000-0000-000000000001)' \
  -H 'Authorization: Bearer synthetic-microsoft-dataverse-token' \
  -H 'Accept: application/json' \
  -H 'OData-Version: 4.0' \
  -H 'OData-MaxVersion: 4.0' \
  -H 'If-Match: W/"470867"' \
  -H 'Content-Type: application/json' \
  --data-binary @-

PowerShell request

$body = '{"name":"Updated Example Co"}'
Invoke-WebRequest `
    -UseBasicParsing `
    -Uri 'https://nottherealapi.com/r/<your-receiver-token>/api/data/v9.2/accounts(00000000-0000-0000-0000-000000000001)' `
    -Method PATCH `
    -Headers @{
    Authorization = 'Bearer synthetic-microsoft-dataverse-token'
    Accept = 'application/json'
    'OData-Version' = '4.0'
    'OData-MaxVersion' = '4.0'
    'If-Match' = 'W/"470867"'
    } `
    -ContentType 'application/json' `
    -Body ([Text.Encoding]::UTF8.GetBytes($body))

Selected synthetic response

HTTP 412
content-type: application/json
odata-version: 4.0

{
  "error": {
    "code": "",
    "message": "The row has changed since it was retrieved."
  }
}

A small JavaScript response boundary

This executable example accepts a Fetch API Response that you already received. It covers the bodyless success and JSON representation cases above. It performs no request, automatic retry or UI update. A non-success response stays an error, with its raw detail available for your error handler.

async function readDataverseResult(response) {
  if (!response.ok) {
    return {
      kind: "error",
      status: response.status,
      retryAfter: response.headers.get("Retry-After"),
      detail: await response.text()
    };
  }
  if (response.status === 204) {
    return {
      kind: "no-content",
      entityUrl: response.headers.get("OData-EntityId")
    };
  }
  // For the separately selected JSON representation response.
  return { kind: "representation", entity: await response.json() };
}

Test a missing identity header too: entityUrl should be null, not a fabricated account URL. Invalid JSON in a supposed representation is still a parsing failure; this example does not silently turn it into success. Windows PowerShell's request sample can throw for HTTP errors: inspect that exception's response, or use the Bash curl sample to see the selected error status and body directly.

Scope, fidelity and sources

This guide targets the module's Dataverse Web API v9.2 Accounts subset. Default fixtures do not persist Accounts, negotiate Prefer or evaluate If-Match dynamically. Fixed IDs, error text, delays and quota-related headers are synthetic example values even when a response shape is labelled Documented. The opt-in bounded lifecycle is separate and requires deployment enablement; nothing here asserts that it is available or enabled.

The source links above were checked on 8 November 2026: Microsoft Learn's create, update, conditional-operation and service-protection documentation. Their semantics describe real Dataverse; the displayed commands and responses describe the selected NotTheRealAPI fixtures. The JavaScript boundary and retry/reconciliation advice are client policy, not additional simulator capabilities.

For the full test surface, see the Dataverse Accounts mock API reference. If your next bug is an HTTP-success stream that never completes, continue with OpenAI Responses partial-output and early-EOF handling.

Continue with your integration test

Read the Dataverse Accounts mock API reference for the full operation and behaviour catalogue. Compare workspace pricing and limits.

Start 7-day free trial

No card required. Your trial starts on workspace creation, with no automatic charge. Subscribing during the trial charges immediately and consumes remaining free time.

Browse all developer guides · OpenAI Responses streaming errors and early EOF

Dataverse 204 No Content: Handle Empty Success | NotTheRealAPI