[GH-ISSUE #7178] Better handling of generic errors raised on organization APIs #10752

Closed
opened 2026-04-13 07:05:15 -05:00 by GiteaMirror · 5 comments
Owner

Originally created by @ferdis on GitHub (Jan 7, 2026).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/7178

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

  1. Create a RootLayout
  2. Call listOrganizations via the server-side API.

Code example (A):

export default async function RootLayout({
  children
}: Props): Promise<ReactNode> {
  const session = await auth.api.getSession({
    headers: await import('next/headers').then((m) => m.headers())
  });

  console.log(`sesssion === ${session}`);
  // session === null

  const org = await auth.api.listOrganizations({
    headers: await import('next/headers').then((m) => m.headers())
  });

  // never reached
  console.log(`org === ${org}`);
}

Example B (messy workaround):

export default async function RootLayout({
  children
}: Props): Promise<ReactNode> {
  const session = await auth.api.getSession({
    headers: await import('next/headers').then((m) => m.headers())
  });

  console.log(`sesssion === ${session}`);
  // session === null

  let orgs = null;
  try 
    const orgs = await auth.api.listOrganizations({
      headers: await import('next/headers').then((m) => m.headers())
    });
  } catch (err) {
    console.log(`listOrganizations errored:');
    console.dir(err);
  }

  console.log(`org === ${org}`);
  // org === null
}

Current vs. Expected behavior

When making API calls to api.listOrganizations (with headers) in a RootLayout, an error is raised which is particularly difficult to discover. For example, I did not pick up the error while busy with development, and only started debugging this after testing.

Server console:

⨯ [Error [APIError]: ] {
  status: 'UNAUTHORIZED',
  body: undefined,
  headers: {},
  statusCode: 401,
  digest: '223797055'
}
 POST /route 500 in 55ms (compile: 4ms, proxy.ts: 5ms, render: 46ms)

Client console:

Uncaught APIError: An error occurred in the Server Components render but no message was provided
    at resolveErrorDev (react-server-dom-turbopack-client.browser.development.js:3181:30)
    at processFullStringRow (react-server-dom-turbopack-client.browser.development.js:4340:23)
    at processFullBinaryRow (react-server-dom-turbopack-client.browser.development.js:4283:7)
    at processBinaryChunk (react-server-dom-turbopack-client.browser.development.js:4506:19)
    at progress (react-server-dom-turbopack-client.browser.development.js:4780:9)

Expected:

The response should be similar to core APIs, such as getSession which returns null when not authenticated. Alternatively, an empty list to maintain the same data type as when authenticated.

What version of Better Auth are you using?

1.4.10

System info

/

{
  "system": {
    "platform": "linux",
    "arch": "arm64",
    // REDACTED
  },
  "node": {
    "version": "v24.11.1",
    "env": "development"
  },
  "packageManager": {
    "name": "npm",
    "version": "11.6.2"
  },
  "frameworks": [
    {
      "name": "next",
      "version": "^16.1.1"
    },
    {
      "name": "react",
      "version": "19.2.3"
    }
  ],
  "databases": [
    {
      "name": "postgres",
      "version": "^3.4.8"
    },
    {
      "name": "drizzle",
      "version": "^0.45.1"
    }
  ]
}

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

Backend

Auth config (if applicable)

import { betterAuth } from "better-auth"
export const auth = betterAuth({
  database: drizzleAdapter(db, {
    provider: 'pg'
  }),

  plugins: [admin(), organizationPlugin(), multiSession()],
  // ...

Additional context

This use case seems significant, as augmenting pages based on user data is a distinctive function of the Layout.

Originally created by @ferdis on GitHub (Jan 7, 2026). Original GitHub issue: https://github.com/better-auth/better-auth/issues/7178 ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce 1. Create a `RootLayout` 2. Call `listOrganizations` via the server-side API. Code example (A): ```ts export default async function RootLayout({ children }: Props): Promise<ReactNode> { const session = await auth.api.getSession({ headers: await import('next/headers').then((m) => m.headers()) }); console.log(`sesssion === ${session}`); // session === null const org = await auth.api.listOrganizations({ headers: await import('next/headers').then((m) => m.headers()) }); // never reached console.log(`org === ${org}`); } ``` Example B (messy workaround): ```ts export default async function RootLayout({ children }: Props): Promise<ReactNode> { const session = await auth.api.getSession({ headers: await import('next/headers').then((m) => m.headers()) }); console.log(`sesssion === ${session}`); // session === null let orgs = null; try const orgs = await auth.api.listOrganizations({ headers: await import('next/headers').then((m) => m.headers()) }); } catch (err) { console.log(`listOrganizations errored:'); console.dir(err); } console.log(`org === ${org}`); // org === null } ``` ### Current vs. Expected behavior When making API calls to `api.listOrganizations` (with headers) in a `RootLayout`, an error is raised which is particularly difficult to discover. For example, I did not pick up the error while busy with development, and only started debugging this after testing. Server console: ``` ⨯ [Error [APIError]: ] { status: 'UNAUTHORIZED', body: undefined, headers: {}, statusCode: 401, digest: '223797055' } POST /route 500 in 55ms (compile: 4ms, proxy.ts: 5ms, render: 46ms) ```` Client console: ``` Uncaught APIError: An error occurred in the Server Components render but no message was provided at resolveErrorDev (react-server-dom-turbopack-client.browser.development.js:3181:30) at processFullStringRow (react-server-dom-turbopack-client.browser.development.js:4340:23) at processFullBinaryRow (react-server-dom-turbopack-client.browser.development.js:4283:7) at processBinaryChunk (react-server-dom-turbopack-client.browser.development.js:4506:19) at progress (react-server-dom-turbopack-client.browser.development.js:4780:9) ``` --- Expected: The response should be similar to core APIs, such as `getSession` which returns `null` when not authenticated. Alternatively, an empty list to maintain the same data type as when authenticated. ### What version of Better Auth are you using? 1.4.10 ### System info / ```bash { "system": { "platform": "linux", "arch": "arm64", // REDACTED }, "node": { "version": "v24.11.1", "env": "development" }, "packageManager": { "name": "npm", "version": "11.6.2" }, "frameworks": [ { "name": "next", "version": "^16.1.1" }, { "name": "react", "version": "19.2.3" } ], "databases": [ { "name": "postgres", "version": "^3.4.8" }, { "name": "drizzle", "version": "^0.45.1" } ] } ``` ### Which area(s) are affected? (Select all that apply) Backend ### Auth config (if applicable) ```typescript import { betterAuth } from "better-auth" export const auth = betterAuth({ database: drizzleAdapter(db, { provider: 'pg' }), plugins: [admin(), organizationPlugin(), multiSession()], // ... ``` ### Additional context This use case seems significant, as augmenting pages based on user data is a distinctive function of the `Layout`.
GiteaMirror added the lockedbug labels 2026-04-13 07:05:15 -05:00
Author
Owner

@better-auth-agent[bot] commented on GitHub (Jan 7, 2026):

It looks like you're experiencing issues with how Better Auth handles errors when calling the listOrganizations API, particularly getting an error if the user isn't authenticated. The current behavior results in an UNAUTHORIZED error being thrown, which can be difficult to handle during development.

Your expectation for the API to return null or an empty list instead is valid and could indeed simplify error handling. This is currently a known issue, and while there isn't a specific resolution yet, it has been noted in discussions regarding improvement of error handling for API calls, including considerations for better responses from organization-related calls [1].

As a next step, you might want to consider implementing error handling in your API calls to gracefully manage these scenarios, or keep an eye out for future updates regarding this specific issue.

Have you tried implementing additional error handling in your listOrganizations calls to provide more user-friendly messages or fallback values? Let me know if you need assistance with that!

If you need more help, tag @better-auth-agent in a comment so I can respond.

DiagramDiscordGitHub

Diagram Join Star

<!-- gh-comment-id:3720273993 --> @better-auth-agent[bot] commented on GitHub (Jan 7, 2026): It looks like you're experiencing issues with how Better Auth handles errors when calling the `listOrganizations` API, particularly getting an error if the user isn't authenticated. The current behavior results in an `UNAUTHORIZED` error being thrown, which can be difficult to handle during development. Your expectation for the API to return `null` or an empty list instead is valid and could indeed simplify error handling. This is currently a known issue, and while there isn't a specific resolution yet, it has been noted in discussions regarding improvement of error handling for API calls, including considerations for better responses from organization-related calls [[1]](https://www.better-auth.com/docs/plugins/organization). As a next step, you might want to consider implementing error handling in your API calls to gracefully manage these scenarios, or keep an eye out for future updates regarding this specific issue. Have you tried implementing additional error handling in your `listOrganizations` calls to provide more user-friendly messages or fallback values? Let me know if you need assistance with that! _If you need more help, tag @better-auth-agent in a comment so I can respond._ <!-- bot:webhook reply v1 --> [Diagram](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) • [Discord](https://discord.gg/fG2XXEuQX3) • [GitHub](https://github.com/Skyvern-AI/Skyvern) [![Diagram](https://img.shields.io/badge/Diagram-2b3137?style=flat-square)](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) [![Join](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&style=flat-square)](https://discord.gg/fG2XXEuQX3) [![Star](https://img.shields.io/badge/star-181717?logo=github&logoColor=white&style=flat-square)](https://github.com/Skyvern-AI/Skyvern)
Author
Owner

@dosubot[bot] commented on GitHub (Jan 7, 2026):

Hi @ferdis! I'm Dosu and I’m helping the better-auth team.

The difference in error handling between getSession and listOrganizations in Better Auth is intentional: getSession returns null when unauthenticated, while listOrganizations throws an APIError with status 401 if no valid session is found. This is enforced by middleware in the organization API routes, which causes unauthenticated requests to crash server components or layouts unless caught source.

The recommended workaround is to always wrap organization API calls (like listOrganizations) in a try/catch block and handle errors gracefully, returning null or an empty list as needed source. Alternatively, fetch the session first and avoid calling organization APIs if unauthenticated. If you already have the session, you can directly query the ORM for organizations to avoid unnecessary session checks and errors source.

There is ongoing discussion about reworking organization API actions to allow them without requiring a session refetch, which may improve error handling in the future, but no recent changes have landed yet source. For now, catching errors and handling unauthenticated states in your application code is the best practice.

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:3720299019 --> @dosubot[bot] commented on GitHub (Jan 7, 2026): <!-- Greeting --> Hi @ferdis! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the better-auth team. <!-- Answer --> The difference in error handling between `getSession` and `listOrganizations` in Better Auth is intentional: `getSession` returns `null` when unauthenticated, while `listOrganizations` throws an `APIError` with status 401 if no valid session is found. This is enforced by middleware in the organization API routes, which causes unauthenticated requests to crash server components or layouts unless caught [`source`](https://github.com/better-auth/better-auth/blob/c31c92f3d24f3ccfb6776d4634e0681c6dee2db5/packages/better-auth/src/plugins/organization/routes/crud-org.ts#L101-L940). The recommended workaround is to always wrap organization API calls (like `listOrganizations`) in a `try/catch` block and handle errors gracefully, returning `null` or an empty list as needed [`source`](https://github.com/better-auth/better-auth/issues/3036). Alternatively, fetch the session first and avoid calling organization APIs if unauthenticated. If you already have the session, you can directly query the ORM for organizations to avoid unnecessary session checks and errors [`source`](https://github.com/better-auth/better-auth/issues/1422#issuecomment-2653078972). There is ongoing discussion about reworking organization API actions to allow them without requiring a session refetch, which may improve error handling in the future, but no recent changes have landed yet [`source`](https://github.com/better-auth/better-auth/issues/1422#issuecomment-2653078972). For now, catching errors and handling unauthenticated states in your application code is the best practice. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/7acdc455-e8e4-4225-8093-c2d8630291b5?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/7acdc455-e8e4-4225-8093-c2d8630291b5?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/7acdc455-e8e4-4225-8093-c2d8630291b5?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/7acdc455-e8e4-4225-8093-c2d8630291b5?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/7acdc455-e8e4-4225-8093-c2d8630291b5?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/7acdc455-e8e4-4225-8093-c2d8630291b5?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/7acdc455-e8e4-4225-8093-c2d8630291b5?feedback_type=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)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=The%20difference%20in%20error%20handling%20between%20%60getSession%60%20and%20%60listOrganizations%60%20in%20Better%20Auth%20is%20intentional%3A%20%60getSession%60%20returns%20%60null%60%20when%20unauthenticated%2C%20while%20%60listOrganizations%60%20throws%20an%20%60APIError%60%20with%20status%20401%20if%20no%20valid%20session%20is%20found.%20This%20is%20enforced%20by%20middleware%20in%20the%20organization%20API%20routes%2C%20which%20causes%20unauthenticated%20requests%20to%20crash%20server%20components%20or%20layouts%20unless%20caught%20%5B%60source%60%5D%28https%3A//github.com/better-auth/better-auth/blob/c31c92f3d24f3ccfb6776d4634e0681c6dee2db5/packages/better-auth/src/plugins/organization/routes/crud-org.ts%23L101-L940%29.%0A%0AThe%20recommended%20workaround%20is%20to%20always%20wrap%20organization%20API%20calls%20%28like%20%60listOrganizations%60%29%20in%20a%20%60try/catch%60%20block%20and%20handle%20errors%20gracefully%2C%20returning%20%60null%60%20or%20an%20empty%20list%20as%20needed%20%5B%60source%60%5D%28https%3A//github.com/better-auth/better-auth/issues/3036%29.%20Alternatively%2C%20fetch%20the%20session%20first%20and%20avoid%20calling%20organization%20APIs%20if%20unauthenticated.%20If%20you%20already%20have%20the%20session%2C%20you%20can%20directly%20query%20the%20ORM%20for%20organizations%20to%20avoid%20unnecessary%20session%20checks%20and%20errors%20%5B%60source%60%5D%28https%3A//github.com/better-auth/better-auth/issues/1422%23issuecomment-2653078972%29.%0A%0AThere%20is%20ongoing%20discussion%20about%20reworking%20organization%20API%20actions%20to%20allow%20them%20without%20requiring%20a%20session%20refetch%2C%20which%20may%20improve%20error%20handling%20in%20the%20future%2C%20but%20no%20recent%20changes%20have%20landed%20yet%20%5B%60source%60%5D%28https%3A//github.com/better-auth/better-auth/issues/1422%23issuecomment-2653078972%29.%20For%20now%2C%20catching%20errors%20and%20handling%20unauthenticated%20states%20in%20your%20application%20code%20is%20the%20best%20practice.)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&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/7178)
Author
Owner

@GautamBytes commented on GitHub (Jan 8, 2026):

Looking into it!

<!-- gh-comment-id:3722795970 --> @GautamBytes commented on GitHub (Jan 8, 2026): Looking into it!
Author
Owner

@ferdis commented on GitHub (Jan 8, 2026):

Thank you @GautamBytes!

<!-- gh-comment-id:3723449857 --> @ferdis commented on GitHub (Jan 8, 2026): Thank you @GautamBytes!
Author
Owner

@Bekacru commented on GitHub (Jan 8, 2026):

It make sense to throw, since you shouldn't be calling list organizations without session. And as you pointed out, you can catch and return null instead

<!-- gh-comment-id:3725103976 --> @Bekacru commented on GitHub (Jan 8, 2026): It make sense to throw, since you shouldn't be calling list organizations without `session`. And as you pointed out, you can catch and return null instead
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#10752