Microsoft Planner – “Make an API Call” suddenly returns “Empty Payload”

:bullseye: What is your goal?

Hi everyone,

I am using the Microsoft 365 Planner – Make an API Call module to update Microsoft Planner task details through the Microsoft Graph API.

The scenario has been working without any problems until now. I have not intentionally changed the request structure, but since today I suddenly receive the following error:

[400] Empty Payload. JSON content expected.

The request uses:

Method: PATCH
Endpoint: /v1.0/planner/tasks/{task-id}/details

A JSON body is configured in the module, and the request also includes the current If-Match ETag from a previous GET request.

The same scenario and payload worked successfully before, so I am wondering whether something recently changed in the Microsoft Planner module, in Make.com, or in the Microsoft Graph API.

Has anyone else encountered this issue recently?

Is there currently a known problem where the Make an API Call module no longer sends the configured request body correctly for PATCH requests?

Any help or confirmation would be appreciated.

:thinking: What is the problem & what have you tried?

Test request in Graph Explorer | Try Microsoft Graph APIs - Microsoft Graph

:clipboard: Error messages or input/output bundles

[
    {
        "url": "/v1.0/planner/tasks/3WLgg-M6sEKt4jGAfG/details",
        "body": "{    \"previewType\": \"reference\",    \"references\": {        \"https%3A//url%2Ede/smth\": {            \"@odata.type\": \"microsoft.graph.plannerExternalReference\",            \"alias\": \"smth\",            \"previewPriority\": \" !\",            \"type\": \"Other\"        }    }}",
        "method": "PATCH",
        "headers": [
            {
                "key": "Content-Type",
                "value": "application/json"
            },
            {
                "key": "If-Match",
                "value": "W/\"JzEtVGFza0RldGFpbHMgQEBAQEBAQEBAQEBAQEBARCc=\""
            },
            {
                "key": "Prefer",
                "value": "return=representation"
            }
        ]
    }
]
[
  {
    "body": null,
    "headers": {},
    "statusCode": null
  }
]

The output bundle is the clue here: your configured input shows a JSON body and headers, but the result shows body: null and headers: {}. That makes me think the request body is being dropped before Microsoft Graph sees it, rather than Graph rejecting the JSON content itself.

I would isolate it with one test outside the Microsoft 365 Planner module:

  1. Use the generic HTTP Make a request module.
  2. Method: PATCH.
  3. URL: https://graph.microsoft.com/v1.0/planner/tasks/{task-id}/details
  4. Body type: Raw.
  5. Content type: application/json.
  6. Headers:
    • Authorization: Bearer token
    • Content-Type: application/json
    • If-Match: your latest ETag
    • Prefer: return=representation
  7. Paste the exact same JSON body there.

If the generic HTTP module works, then the issue is probably in Make’s Microsoft 365 Planner Make an API Call module handling PATCH bodies. In that case the practical workaround is to keep using the generic HTTP module for this endpoint and report the module regression to Make support.

If the generic HTTP module fails with the same Graph error, then I would check these two things next:

  • Make sure the body is not being double-encoded as a string. Graph should receive a JSON object, not a quoted JSON string.
  • Re-fetch the task details immediately before PATCH and use that fresh If-Match value. Planner details ETags can go stale quickly.

I would also temporarily remove Prefer: return=representation for one test. It should not cause an empty payload error, but removing optional headers helps confirm whether the failure is purely body transmission or something else in the request.

Two things in that error string narrow this down a bit further.

“Empty Payload. JSON content expected” reads like zero bytes arrived, not wrong-shaped bytes. A double-encoded body would still be valid JSON on the wire — a string rather than an object — and Graph would complain about the shape instead. So the body isn’t being mangled, it’s not being sent at all. Same for the ETag: a stale one comes back as 412 Precondition Failed, not 400, so that’s probably not it either.

Which leaves the question worth answering first: does it fail on every task, or only some?

That single answer splits the problem in half. Fails on all of them, and it’s configuration or the module itself, and the generic HTTP comparison above is exactly the right next step. Fails on only some, and the module is innocent — the body is assembled from mapped values, and on those runs something upstream is resolving to empty. Make renders that as an empty body and sends it without complaining, so nothing errors until Graph does.

“It worked before and I changed nothing” fits the second case better than the first. Configuration doesn’t drift on its own; data does. If a field the body maps from is occasionally absent now, you get exactly this: intermittent, no local error, and a 400 from the far end.

Worth checking the raw body on a failed execution rather than the configured JSON — the module shows what you wrote, not what it rendered.

Agreed, that is the better split.

I would check it in this order:

  1. Pick one failed run and open the module output for that execution, not the module setup screen.
  2. Look at the actual rendered request body. If it is empty there, the issue is upstream mapping or data availability.
  3. Run the same task again with a hard coded minimal body, for example just previewType. If that works, the Planner API and endpoint are probably fine.
  4. Compare a successful task and failed task side by side. The missing mapped value should usually show up pretty quickly.

If it fails for every task with a hard coded body, then I would go back to the generic HTTP test because that points more toward the Make Planner module. If only the dynamic body fails, I would trace the bundle field that builds references and add a filter or fallback before the PATCH step so the module never sends an empty body.

So yes: do not trust the configured JSON view yet. The rendered raw body from the failed execution is the source of truth.