[GH-ISSUE #8549] [scim plugin] Valid patch request throws 400 #11116

Open
opened 2026-04-13 07:29:31 -05:00 by GiteaMirror · 1 comment
Owner

Originally created by @formatlos on GitHub (Mar 11, 2026).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/8549

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

When the IDP sends a patch request on a user and the data is already up-to-date the endpoint returns a 400

{"schemas":["urn:ietf:params:scim:api:messages:2.0:Error"],"status":"400","detail":"No valid fields to update"}

It doens't seem distinguish between the the request not sending any appropriate fields vs. the field being found but already up-to-date.

Current vs. Expected behavior

Expectation would be that the endpoint returns with success (204)

What version of Better Auth are you using?

1.5.4

System info

{
  "system": {
    "platform": "darwin",
    "arch": "arm64",
    "version": "Darwin Kernel Version 24.6.0: Wed Nov  5 21:33:58 PST 2025; root:xnu-11417.140.69.705.2~1/RELEASE_ARM64_T6000",
    "release": "24.6.0",
    "cpuCount": 10,
    "cpuModel": "Apple M1 Max",
    "totalMemory": "64.00 GB",
    "freeMemory": "0.53 GB"
  },
  "node": {
    "version": "v22.14.0",
    "env": "development"
  },
  "packageManager": {
    "name": "npm",
    "version": "10.9.2"
  },
  "frameworks": [
    {
      "name": "fastify",
      "version": "^5.5.0"
    }
  ],
  "databases": [
    {
      "name": "pg",
      "version": "^8.17.2"
    },
    {
      "name": "postgres",
      "version": "^3.4.8"
    },
    {
      "name": "@prisma/client",
      "version": "^6.18.0"
    },
    {
      "name": "kysely",
      "version": "^0.28.9"
    }
  ],
  "betterAuth": {
    "version": "^1.5.4"
    }
  }
}

Which area(s) are affected? (Select all that apply)

Backend

Auth config (if applicable)

import { betterAuth } from "better-auth"
export const auth = betterAuth({
  emailAndPassword: {  
    enabled: true
  },
});

Additional context

No response

Originally created by @formatlos on GitHub (Mar 11, 2026). Original GitHub issue: https://github.com/better-auth/better-auth/issues/8549 ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce When the IDP sends a patch request on a user and the data is already up-to-date the endpoint returns a 400 ``` {"schemas":["urn:ietf:params:scim:api:messages:2.0:Error"],"status":"400","detail":"No valid fields to update"} ``` It doens't seem distinguish between the the request not sending any appropriate fields vs. the field being found but already up-to-date. ### Current vs. Expected behavior Expectation would be that the endpoint returns with success (204) ### What version of Better Auth are you using? 1.5.4 ### System info ```bash { "system": { "platform": "darwin", "arch": "arm64", "version": "Darwin Kernel Version 24.6.0: Wed Nov 5 21:33:58 PST 2025; root:xnu-11417.140.69.705.2~1/RELEASE_ARM64_T6000", "release": "24.6.0", "cpuCount": 10, "cpuModel": "Apple M1 Max", "totalMemory": "64.00 GB", "freeMemory": "0.53 GB" }, "node": { "version": "v22.14.0", "env": "development" }, "packageManager": { "name": "npm", "version": "10.9.2" }, "frameworks": [ { "name": "fastify", "version": "^5.5.0" } ], "databases": [ { "name": "pg", "version": "^8.17.2" }, { "name": "postgres", "version": "^3.4.8" }, { "name": "@prisma/client", "version": "^6.18.0" }, { "name": "kysely", "version": "^0.28.9" } ], "betterAuth": { "version": "^1.5.4" } } } ``` ### Which area(s) are affected? (Select all that apply) Backend ### Auth config (if applicable) ```typescript import { betterAuth } from "better-auth" export const auth = betterAuth({ emailAndPassword: { enabled: true }, }); ``` ### Additional context _No response_
GiteaMirror added the enterprisebug labels 2026-04-13 07:29:31 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Mar 11, 2026):

I can confirm this behavior and pinpoint the cause. The error is thrown in packages/scim/src/routes.ts (lines 878-885):

if (
    Object.keys(userPatch).length === 0 &&
    Object.keys(accountPatch).length === 0
) {
    throw new SCIMAPIError("BAD_REQUEST", {
        detail: "No valid fields to update",
    });
}

The issue is that the patch operation logic correctly detects when values are unchanged and skips those updates, but when all values are unchanged, both patch objects end up empty—triggering this 400 error.

Your expectation is correct. Per SCIM 2.0 (RFC 7644), PATCH operations should be idempotent, so a request that results in no changes should still succeed rather than return an error. This is a bug in the current implementation.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

<!-- gh-comment-id:4038908847 --> @dosubot[bot] commented on GitHub (Mar 11, 2026): <!-- Answer --> I can confirm this behavior and pinpoint the cause. The error is thrown in [`packages/scim/src/routes.ts` (lines 878-885)](https://github.com/better-auth/better-auth/blob/b9e54c9afacdc4e7f1a1b1b4d4914ac2ff25b340/packages/scim/src/routes.ts#L878-L885): ```typescript if ( Object.keys(userPatch).length === 0 && Object.keys(accountPatch).length === 0 ) { throw new SCIMAPIError("BAD_REQUEST", { detail: "No valid fields to update", }); } ``` The issue is that the [patch operation logic](https://github.com/better-auth/better-auth/blob/b9e54c9afacdc4e7f1a1b1b4d4914ac2ff25b340/packages/scim/src/patch-operations.ts#L101-L106) correctly detects when values are unchanged and skips those updates, but when *all* values are unchanged, both patch objects end up empty—triggering this 400 error. Your expectation is correct. Per SCIM 2.0 (RFC 7644), PATCH operations should be idempotent, so a request that results in no changes should still succeed rather than return an error. This is a bug in the current implementation. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot?utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=brand-link).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/b1fce3bb-8151-41dc-bf95-6d2c57307004?feedback_type=great_response&utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=feedback-great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/b1fce3bb-8151-41dc-bf95-6d2c57307004?feedback_type=irrelevant_answer&utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=feedback-irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/b1fce3bb-8151-41dc-bf95-6d2c57307004?feedback_type=incorrect_sources&utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=feedback-incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/b1fce3bb-8151-41dc-bf95-6d2c57307004?feedback_type=too_verbose&utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=feedback-too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/b1fce3bb-8151-41dc-bf95-6d2c57307004?feedback_type=hallucination&utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=feedback-hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/b1fce3bb-8151-41dc-bf95-6d2c57307004?feedback_type=bug_report&utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=feedback-bug_report) | [Other](https://app.dosu.dev/response-feedback/b1fce3bb-8151-41dc-bf95-6d2c57307004?feedback_type=other&utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=feedback-other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=chat-badge)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=I%20can%20confirm%20this%20behavior%20and%20pinpoint%20the%20cause.%20The%20error%20is%20thrown%20in%20%5B%60packages/scim/src/routes.ts%60%20%28lines%20878-885%29%5D%28https%3A//github.com/better-auth/better-auth/blob/b9e54c9afacdc4e7f1a1b1b4d4914ac2ff25b340/packages/scim/src/routes.ts%23L878-L885%29%3A%0A%0A%60%60%60typescript%0Aif%20%28%0A%20%20%20%20Object.keys%28userPatch%29.length%20%3D%3D%3D%200%20%26%26%0A%20%20%20%20Object.keys%28accountPatch%29.length%20%3D%3D%3D%200%0A%29%20%7B%0A%20%20%20%20throw%20new%20SCIMAPIError%28%22BAD_REQUEST%22%2C%20%7B%0A%20%20%20%20%20%20%20%20detail%3A%20%22No%20valid%20fields%20to%20update%22%2C%0A%20%20%20%20%7D%29%3B%0A%7D%0A%60%60%60%0A%0AThe%20issue%20is%20that%20the%20%5Bpatch%20operation%20logic%5D%28https%3A//github.com/better-auth/better-auth/blob/b9e54c9afacdc4e7f1a1b1b4d4914ac2ff25b340/packages/scim/src/patch-operations.ts%23L101-L106%29%20correctly%20detects%20when%20values%20are%20unchanged%20and%20skips%20those%20updates%2C%20but%20when%20%2Aall%2A%20values%20are%20unchanged%2C%20both%20patch%20objects%20end%20up%20empty%E2%80%94triggering%20this%20400%20error.%0A%0AYour%20expectation%20is%20correct.%20Per%20SCIM%202.0%20%28RFC%207644%29%2C%20PATCH%20operations%20should%20be%20idempotent%2C%20so%20a%20request%20that%20results%20in%20no%20changes%20should%20still%20succeed%20rather%20than%20return%20an%20error.%20This%20is%20a%20bug%20in%20the%20current%20implementation.)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot?utm_source=github&utm_medium=bot-comment&utm_campaign=github-assistant&utm_content=join-discord)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/8549)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#11116