Skip to content

Globals with _status set to draft returns partial data instead of returning an API error #14096

@mateo-m

Description

@mateo-m

Describe the Bug

I might be missing something in the documentation, but having versions & drafts + scheduled publishing enabled ends up making globals' access control behave in a weird way (I haven't tested for normal collections yet).

I was expecting that any GET call made to API routes like http://localhost:3000/api/globals/<global_slug> where said global isn't published would get a serialized APIError as a response when the Access Control's read field was defined to only return a global if its _status is set to published.

Example of a global config:

{
  // ...
  fields: [
    {
      name: "title",
      type: "text",
      admin: {
        description: "The title of the announcement.",
      },
      unique: true,
      required: true,
      localized: true,
    },
  ],
  versions: {
    drafts: {
      autosave: {
        interval: 30_000, // Autosave every 30 seconds
        showSaveDraftButton: true,
      },
      schedulePublish: true,
    },
  },
  access: {
    read: ({ req: { user } }) => {
      if (!!user?.roles?.includes("admin") || !!user?.roles?.includes("editor")) {
        return true;
      }

      return {
        _status: {
          equals: "published",
        },
      };
    },
    update: ({ req: { user } }) => {
      if (user?.roles?.includes("admin") || user?.roles?.includes("editor")) {
        return true;
      }

      return false;
    },
  },
  // ...
}

But instead, the response is an object with a single field (_status):

{
  "_status": "draft"
}

I did run my GET call without being authenticated (incognito window) to make sure I don't end up in the early return.

This is kind of a weird middle ground, because it doesn't return the expected APIError saying that this action isn't permitted.
Instead, it returns a partial object with only the _status field in it.

Link to the code that reproduces this issue

https://github.com/mateo-m/repro-draft-access-control-payload

Reproduction Steps

  1. Clone the repository I created to make sure the issue can be reproduced.
  2. Run the Payload app.
  3. Try to fetch the Announcement.

Here are the different scenarios you can test where the weird behavior is visible:

  • before saving any data
  • after saving data as draft but without publishing it
  • save data & publish it, then unpublish it

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

Not sure

Environment Info

Binaries:
  Node: 22.16.0
  npm: 11.4.2
  Yarn: 1.22.22
  pnpm: 10.17.1
Relevant Packages:
  payload: 3.58.0
  next: 15.4.4
  @payloadcms/db-postgres: 3.58.0
  @payloadcms/email-nodemailer: 3.58.0
  @payloadcms/graphql: 3.58.0
  @payloadcms/next/utilities: 3.58.0
  @payloadcms/payload-cloud: 3.58.0
  @payloadcms/richtext-lexical: 3.58.0
  @payloadcms/translations: 3.58.0
  @payloadcms/ui/shared: 3.58.0
  react: 19.1.0
  react-dom: 19.1.0
Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 25.1.0: Fri Sep 19 19:12:09 PDT 2025; root:xnu-12377.40.77.505.1~4/RELEASE_ARM64_T6020
  Available memory (MB): 32768
  Available CPU cores: 12

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions