Skip to content

feat: generate separate input and output types for collections and globals#17075

Open
AlessioGr wants to merge 14 commits into
mainfrom
feat/input-output-types
Open

feat: generate separate input and output types for collections and globals#17075
AlessioGr wants to merge 14 commits into
mainfrom
feat/input-output-types

Conversation

@AlessioGr

@AlessioGr AlessioGr commented Jun 22, 2026

Copy link
Copy Markdown
Member

Payload generates one TypeScript type per collection and global, describing what you get back when you read. But that same type is also used for what you write (create/update), and the two shapes differ. As join field, for example, would be included in the output type - but you never write data for a join field. One type can't be right for both.

This PR can generate a second type per entity - a write type - turned on with typescript.generateInputTypes: true. It's off by default:

  • Post - the read type. Unchanged, fully backwards compatible.
  • PostInput - the new write type. Relationships are IDs only; auto-managed, virtual, and join fields are removed; defaultValue fields are optional.

Off by default means regenerating an existing project gives the same file as before - nothing breaks unless you turn it on. The only thing using it today is @payloadcms/plugin-mcp, which gets the correct write schema either way (it builds that at runtime and ignores the flag). Turn it on if you also want PostInput (and collectionsInput / globalsInput on Config) to type a form payload, seed script, or API client.

Why opt-in? create/update still use the read type for data (see below), so the write type isn't part of the main write path. Generating it for everyone by default would add code and a second type to learn, for something most people wouldn't use.

Why a separate type - read and write differ in more than relationships

It's not just whether a relationship is populated. Here's every place the write type differs from the read type:

# Category Output type Input type Why they differ Type test
1 Relationship / upload (string | null) | User string | null Depth can populate on read; you only ever write an ID. Covers single, hasMany, and the value of polymorphic { relationTo, value }. L1354
1b Rel/upload nodes inside richText populated node ID-only node Lexical is variant-aware: input emits SerializedRelationshipNodeInput/SerializedUploadNodeInput + …Input blocks - see Rich text below. L1369
2 id required optional Read always has it; on create you may supply a custom ID or let Payload generate one. L1374
3 createdAt / updatedAt required omitted Auto-managed. L1379
4 _status (drafts) present omitted Auto-managed by the versions/drafts system; omitted from the input shape. L1386
5 defaultValue fields required / present optional The default fills it in if omitted. A required field with a default was wrongly mandatory before. L1391
6 Virtual fields present omitted Computed / relationship-derived, read-only. L1396
7 Join fields present (paginated related docs) omitted Computed from the inverse relationship; not writable. L1401
8 Auth collection discriminator present omitted The read-side User-union discriminator; not part of create/update data. L1406

Before and after

Given this config:

{
  slug: 'posts',
  fields: [
    { name: 'title', type: 'text', required: true },
    { name: 'status', type: 'select', options: ['draft', 'published'], defaultValue: 'draft', required: true },
    { name: 'author', type: 'relationship', relationTo: 'authors' },
    { name: 'categories', type: 'relationship', relationTo: 'categories', hasMany: true },
  ],
}

The read type doesn't change:

export interface Post {
  id: string
  title: string
  status: 'draft' | 'published'
  author?: (string | null) | Author
  categories?: (string | Category)[] | null
  updatedAt: string
  createdAt: string
}

With the flag on, you also get the write type:

export interface PostInput {
  id?: string // optional - a custom ID, or let Payload generate one (optional, never null)
  title: string // required (no default)
  status?: 'draft' | 'published' // optional, because it has a defaultValue (optional, never null)
  author?: string | null // ID only
  categories?: string[] | null // array of IDs only
  // no createdAt / updatedAt
}

The write types also appear on Config, next to the existing maps:

export interface Config {
  collections: { posts: Post /* … */ }
  collectionsInput: { posts: PostInput /* … */ }
  globals: { menu: Menu /* … */ }
  globalsInput: { menu: MenuInput /* … */ }
  // …
}

How it works

One flag, variant: 'input' | 'output' (default 'output'), runs through the existing builders in configToJSONSchema.ts. No separate code path; the read side is unchanged.

  • fieldsToJSONSchema - for input: relationship/upload fields become IDs only, defaultValue fields become optional, virtual/join fields are skipped. Named interfaces (groups, tabs, arrays, selects, blocks) only get an Input suffix when their write shape actually differs - if it's identical they share one type, so a relationship-free Meta gets no MetaInput copy.
  • entityToJSONSchema - for input: id becomes optional; createdAt, updatedAt, _status, and the auth collection field are removed; the name gets an Input suffix. Note: optional ≠ nullable. A field input only makes optional (id, defaulted fields) stays non-null (id?: string, not id?: string | null), so PostInput stays a subset of the read type and can still be passed to create/update.
  • registerBlockInterface and entityToStandaloneJSONSchema also take the variant: a blocks field gives Hero and HeroInput when they differ, one Hero when they don't.
  • configToJSONSchema - when the flag is on, also writes ${slug}_input types and adds collectionsInput / globalsInput to Config; json-schema-to-typescript turns those into PostInput, MenuInput, etc.
  • Field-level field.jsonSchema transforms now get variant, so a custom transform can differ for input vs output.
  • The rich-text editor's jsonSchema callback gets variant too - see below.
  • New exports: a SchemaVariant type and the generateInputTypes flag.

Rich text

Lexical handles both variants. Its types come from named Serialized*Node types via tsType, and most are generic over their children or block fields, so the input union just plugs in the input types:

LexicalNodes_...Input =  | SerializedParagraphNode<LexicalNodes_...Input>    // recursion auto-resolves to the input union
                      | SerializedBlockNode<CtaInput>                 // reused generic, input block fields
                      | SerializedUploadNodeInput<"media">;           // ID-only

Only two node types put the full document directly in their definition - SerializedRelationshipNode and SerializedUploadNode - so those get a hand-written ID-only version (SerializedRelationshipNodeInput / SerializedUploadNodeInput). Everything else (text, paragraph, heading, lists, tables, links, blocks) is reused.

Both also stopped hardcoding number | string for a relationship's value - they now use each collection's real ID type: output nodes use Config['collections'][TSlug]['id'] | Config['collections'][TSlug], input nodes use Config['collections'][TSlug]['id'] (backed by a new exported IDTypeForCollectionSlug<TSlug> helper).

Node unions are named by a content hash; an input union is LexicalNodes_<hash>_Input to tell it apart from the output one. An editor with no relationships has identical input and output unions, so they share one LexicalNodes_<hash> (no _Input copy). Same for blocks and named interfaces: the Input suffix only appears when the write shape differs.

MCP cleanup

This is the main place the input types are used today. @payloadcms/plugin-mcp now calls entityToStandaloneJSONSchema({ variant: 'input' }). Because that variant is already correct, all the schema cleanup MCP used to do is gone - the input variant has zero collection $refs anywhere, including in rich text:

  • Removed removeVirtualFieldsFromSchema - input already omits virtual fields.
  • Removed removeManagedFields - input already omits the managed id.
  • Removed relationshipsToIds - input relationship/upload values are already IDs, so there's no oneOf: [id, $ref] left to simplify.
  • Kept only the MCP-specific cleanup (point→object, const-union merge, dedup, name shortening).

Why create/update still use the read type

The write types exist and MCP uses them, but the Local API (create, update, updateByID, duplicate, updateGlobal) still types data against the read type (Post, not PostInput). I decided against switching it, for two reasons.

Read-modify-write is common and valid at runtime. With the write type, it stops compiling as soon as you read at depth > 0:

const post = await payload.findByID({ collection: 'posts', id, depth: 1 })
// depth: 1 → post.author is the *populated* User document, not an ID
await payload.update({
  collection: 'posts',
  id,
  data: { author: post.author }, // ❌ the write type wants an ID, not a populated doc
})

Spreading a read document (data: { ...post, title }) or writing rich text back breaks the same way.

The write type would be stricter than the runtime. Payload accepts a populated relationship on write and pulls the ID out. Rejecting that in the types rejects working code, pushing people to as any - worse than a loose type.

We may switch the Local API to a real write type later, but that needs read-modify-write solved first: the write type would accept a relationship as either an ID or the full document (id | doc, what the runtime already does) while keeping id, defaulted, and managed fields optional. Bigger change, follow-up. For now the write types are safe to use - they're assignable to what create/update accept.

Where the write types are safe to use today

  • @payloadcms/plugin-mcp uses the input schema directly.
  • Opt in via Config['collectionsInput']['posts'] or the exported PostInput to type a write helper, form payload, or seed script.

A few other notes

What the write type keeps vs. removes. It keeps everything you can write, as optional - including fields only writable with overrideAccess (salt, hash, resetPasswordToken, …) and upload metadata (url, filename, sizes, …). Removing those was rejected: the only "never written" signal is a field-level access: () => false, which overrideAccess bypasses, so removing them would make the type stricter than the runtime. It removes the truly read-only stuff: virtual and join fields, the auth collection field, and the auto-managed createdAt / updatedAt / _status - those three are settable via data but rarely set on purpose, so they're dropped like Prisma/Drizzle drop generated timestamps. (One honest inconsistency: we drop createdAt/updatedAt/_status but keep salt/hash, which are just as managed - worth reconciling if we revisit the write type.)

Off by default. generateInputTypes defaults to false: regenerating an existing project gives the same output as before, so this PR breaks nothing unless you turn it on. Here, only test/types opts in (for the type tests); every other suite regenerates unchanged. The flag's JSDoc has a @todo for turning it on by default (the read-modify-write problem above).


@github-actions

github-actions Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

📦 esbuild Bundle Analysis for payload

This analysis was generated by esbuild-bundle-analyzer. 🤖

Meta File Out File Size (raw) Note
packages/next/meta_index.json esbuild/index.js 201.84 KB ✅ No change
packages/payload/meta_index.json esbuild/index.js 1.40 MB ⚠️ +1.13 KB (+0.1%)
packages/payload/meta_shared.json esbuild/exports/shared.js 192.64 KB ✅ No change
packages/richtext-lexical/meta_client.json esbuild/exports/client_optimized/index.js 305.77 KB ✅ No change
packages/ui/meta_client.json esbuild/exports/client_optimized/index.js 1.37 MB ✅ No change
packages/ui/meta_shared.json esbuild/exports/shared_optimized/index.js 18.66 KB ✅ No change
Largest paths These visualization shows top 20 largest paths in the bundle.

Meta file: packages/next/meta_index.json, Out file: esbuild/index.js

Path Size
../../node_modules ${{\color{Goldenrod}{ ████████████████████████▋ }}}$ 98.9%, 197.86 KB
dist/adapters/router.js ${{\color{Goldenrod}{ }}}$ 0.3%, 663 B
dist/adapters/server.js ${{\color{Goldenrod}{ }}}$ 0.3%, 533 B
dist/adapters/layout.js ${{\color{Goldenrod}{ }}}$ 0.3%, 526 B
dist/adapters/views.js ${{\color{Goldenrod}{ }}}$ 0.2%, 409 B
dist/esbuildEntry.js ${{\color{Goldenrod}{ }}}$ 0.0%, 0 B

Meta file: packages/payload/meta_index.json, Out file: esbuild/index.js

Path Size
../../node_modules ${{\color{Goldenrod}{ █████████████████▎ }}}$ 69.1%, 960.52 KB
dist/fields/hooks ${{\color{Goldenrod}{ ▊ }}}$ 3.2%, 43.88 KB
dist/collections/operations ${{\color{Goldenrod}{ ▊ }}}$ 3.1%, 42.68 KB
dist/utilities/configToJSONSchema.js ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 16.00 KB
dist/auth/operations ${{\color{Goldenrod}{ ▎ }}}$ 1.1%, 15.63 KB
dist/globals/operations ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 13.36 KB
dist/fields/config ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 13.27 KB
dist/queues/operations ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 12.63 KB
dist/fields/validations.js ${{\color{Goldenrod}{ ▏ }}}$ 0.8%, 10.57 KB
dist/bin/generateImportMap ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 9.67 KB
dist/collections/config ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 9.21 KB
dist/config/orderable ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 8.07 KB
dist/uploads/fetchAPI-multipart ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.80 KB
dist/index.js ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.77 KB
dist/hierarchy/utils ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 7.64 KB
dist/database/migrations ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 7.55 KB
dist/collections/endpoints ${{\color{Goldenrod}{ }}}$ 0.4%, 6.12 KB
dist/queues/config ${{\color{Goldenrod}{ }}}$ 0.4%, 5.59 KB
dist/auth/strategies ${{\color{Goldenrod}{ }}}$ 0.4%, 5.43 KB
dist/utilities/telemetry ${{\color{Goldenrod}{ }}}$ 0.4%, 5.31 KB
(other) ${{\color{Goldenrod}{ ███████▋ }}}$ 30.9%, 429.85 KB

Meta file: packages/payload/meta_shared.json, Out file: esbuild/exports/shared.js

Path Size
../../node_modules ${{\color{Goldenrod}{ ███████████████████▉ }}}$ 79.5%, 150.12 KB
dist/fields/validations.js ${{\color{Goldenrod}{ █▍ }}}$ 5.6%, 10.57 KB
dist/config/orderable ${{\color{Goldenrod}{ ▍ }}}$ 1.7%, 3.13 KB
dist/fields/baseFields ${{\color{Goldenrod}{ ▍ }}}$ 1.5%, 2.79 KB
dist/utilities/deepCopyObject.js ${{\color{Goldenrod}{ ▎ }}}$ 1.4%, 2.69 KB
dist/auth/cookies.js ${{\color{Goldenrod}{ ▏ }}}$ 0.8%, 1.55 KB
dist/utilities/flattenTopLevelFields.js ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 1.42 KB
dist/fields/config ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 1.29 KB
dist/utilities/getVersionsConfig.js ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 1.04 KB
dist/utilities/flattenAllFields.js ${{\color{Goldenrod}{ }}}$ 0.4%, 794 B
dist/utilities/unflatten.js ${{\color{Goldenrod}{ }}}$ 0.4%, 779 B
dist/utilities/sanitizeUserDataForEmail.js ${{\color{Goldenrod}{ }}}$ 0.4%, 713 B
dist/utilities/getFieldPermissions.js ${{\color{Goldenrod}{ }}}$ 0.3%, 651 B
dist/collections/config ${{\color{Goldenrod}{ }}}$ 0.3%, 570 B
dist/bin/generateImportMap ${{\color{Goldenrod}{ }}}$ 0.3%, 561 B
dist/auth/sessions.js ${{\color{Goldenrod}{ }}}$ 0.3%, 525 B
dist/fields/getFieldPaths.js ${{\color{Goldenrod}{ }}}$ 0.3%, 485 B
dist/utilities/appendDateTimezoneSelectFields.js ${{\color{Goldenrod}{ }}}$ 0.2%, 432 B
dist/utilities/getSafeRedirect.js ${{\color{Goldenrod}{ }}}$ 0.2%, 423 B
dist/utilities/deepMerge.js ${{\color{Goldenrod}{ }}}$ 0.2%, 413 B
(other) ${{\color{Goldenrod}{ █████▏ }}}$ 20.5%, 38.71 KB

Meta file: packages/richtext-lexical/meta_client.json, Out file: esbuild/exports/client_optimized/index.js

Path Size
dist/features/blocks ${{\color{Goldenrod}{ ███ }}}$ 12.3%, 37.13 KB
dist/lexical/ui ${{\color{Goldenrod}{ ██▊ }}}$ 11.3%, 34.16 KB
dist/lexical/plugins ${{\color{Goldenrod}{ ██▋ }}}$ 10.9%, 32.88 KB
dist/features/experimental_table ${{\color{Goldenrod}{ ██▎ }}}$ 9.0%, 27.16 KB
dist/packages/@lexical ${{\color{Goldenrod}{ █▋ }}}$ 6.5%, 19.80 KB
dist/features/link ${{\color{Goldenrod}{ █▌ }}}$ 6.2%, 18.83 KB
dist/features/toolbars ${{\color{Goldenrod}{ █▍ }}}$ 5.5%, 16.58 KB
dist/features/upload ${{\color{Goldenrod}{ █▏ }}}$ 4.7%, 14.09 KB
dist/features/textState ${{\color{Goldenrod}{ ▉ }}}$ 3.7%, 11.08 KB
dist/features/relationship ${{\color{Goldenrod}{ ▊ }}}$ 3.2%, 9.61 KB
dist/lexical/utils ${{\color{Goldenrod}{ ▋ }}}$ 2.9%, 8.79 KB
dist/features/converters ${{\color{Goldenrod}{ ▋ }}}$ 2.8%, 8.36 KB
dist/utilities/fieldsDrawer ${{\color{Goldenrod}{ ▋ }}}$ 2.7%, 8.12 KB
dist/features/debug ${{\color{Goldenrod}{ ▌ }}}$ 2.4%, 7.40 KB
dist/lexical/config ${{\color{Goldenrod}{ ▍ }}}$ 1.7%, 5.08 KB
dist/features/lists ${{\color{Goldenrod}{ ▍ }}}$ 1.7%, 5.00 KB
dist/features/format ${{\color{Goldenrod}{ ▎ }}}$ 1.1%, 3.46 KB
dist/lexical/LexicalEditor.js ${{\color{Goldenrod}{ ▎ }}}$ 1.1%, 3.23 KB
dist/features/horizontalRule ${{\color{Goldenrod}{ ▎ }}}$ 1.1%, 3.18 KB
dist/field/Field.js ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 2.83 KB
(other) ${{\color{Goldenrod}{ █████████████████████▉ }}}$ 87.7%, 265.41 KB

Meta file: packages/ui/meta_client.json, Out file: esbuild/exports/client_optimized/index.js

Path Size
../../node_modules ${{\color{Goldenrod}{ ██████████▋ }}}$ 42.6%, 580.42 KB
dist/elements/Hierarchy ${{\color{Goldenrod}{ ▊ }}}$ 3.2%, 43.02 KB
dist/elements/BulkUpload ${{\color{Goldenrod}{ ▌ }}}$ 2.1%, 28.33 KB
dist/views/Version ${{\color{Goldenrod}{ ▌ }}}$ 2.0%, 27.40 KB
dist/views/HierarchyList ${{\color{Goldenrod}{ ▍ }}}$ 1.5%, 20.43 KB
dist/elements/Table ${{\color{Goldenrod}{ ▎ }}}$ 1.4%, 19.37 KB
dist/views/Dashboard ${{\color{Goldenrod}{ ▎ }}}$ 1.3%, 17.73 KB
dist/views/Edit ${{\color{Goldenrod}{ ▎ }}}$ 1.3%, 17.45 KB
dist/elements/WhereBuilder ${{\color{Goldenrod}{ ▎ }}}$ 1.3%, 17.41 KB
dist/forms/Form ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 15.89 KB
dist/fields/Relationship ${{\color{Goldenrod}{ ▎ }}}$ 1.1%, 15.48 KB
dist/fields/Blocks ${{\color{Goldenrod}{ ▎ }}}$ 1.1%, 15.06 KB
dist/fields/Upload ${{\color{Goldenrod}{ ▎ }}}$ 1.1%, 14.40 KB
dist/elements/QueryPresets ${{\color{Goldenrod}{ ▏ }}}$ 0.8%, 10.75 KB
dist/elements/ReactSelect ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 9.07 KB
dist/views/List ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 8.78 KB
dist/elements/PublishButton ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 8.77 KB
dist/elements/HTMLDiff ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 8.38 KB
dist/elements/LivePreview ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 8.26 KB
dist/elements/UserMenu ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 8.17 KB
(other) ${{\color{Goldenrod}{ ██████████████▎ }}}$ 57.4%, 782.62 KB

Meta file: packages/ui/meta_shared.json, Out file: esbuild/exports/shared_optimized/index.js

Path Size
dist/graphics/Logo ${{\color{Goldenrod}{ ███████▋ }}}$ 30.9%, 5.57 KB
../../node_modules ${{\color{Goldenrod}{ ███▋ }}}$ 14.7%, 2.65 KB
dist/graphics/Icon ${{\color{Goldenrod}{ ██▏ }}}$ 8.5%, 1.52 KB
dist/utilities/formatDocTitle ${{\color{Goldenrod}{ █▊ }}}$ 7.3%, 1.32 KB
dist/providers/TableColumns ${{\color{Goldenrod}{ █▏ }}}$ 4.8%, 866 B
dist/utilities/getGlobalData.js ${{\color{Goldenrod}{ █ }}}$ 4.2%, 762 B
dist/utilities/api.js ${{\color{Goldenrod}{ █ }}}$ 4.2%, 756 B
dist/utilities/groupNavItems.js ${{\color{Goldenrod}{ █ }}}$ 4.1%, 745 B
dist/elements/Translation ${{\color{Goldenrod}{ ▋ }}}$ 2.7%, 493 B
dist/utilities/handleTakeOver.js ${{\color{Goldenrod}{ ▌ }}}$ 2.4%, 440 B
dist/utilities/traverseForLocalizedFields.js ${{\color{Goldenrod}{ ▌ }}}$ 2.3%, 419 B
dist/elements/withMergedProps ${{\color{Goldenrod}{ ▍ }}}$ 1.9%, 339 B
dist/utilities/getNavGroups.js ${{\color{Goldenrod}{ ▍ }}}$ 1.9%, 338 B
dist/utilities/getVisibleEntities.js ${{\color{Goldenrod}{ ▍ }}}$ 1.8%, 329 B
dist/elements/WithServerSideProps ${{\color{Goldenrod}{ ▎ }}}$ 1.3%, 232 B
dist/utilities/handleGoBack.js ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 180 B
dist/fields/mergeFieldStyles.js ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 157 B
dist/utilities/handleBackToDashboard.js ${{\color{Goldenrod}{ ▏ }}}$ 0.8%, 152 B
dist/forms/Form ${{\color{Goldenrod}{ ▏ }}}$ 0.8%, 148 B
dist/utilities/abortAndIgnore.js ${{\color{Goldenrod}{ ▏ }}}$ 0.8%, 146 B
(other) ${{\color{Goldenrod}{ █████████████████▎ }}}$ 69.1%, 12.47 KB
Details

Next to the size is how much the size has increased or decreased compared with the base branch of this PR.

  • ‼️: Size increased by 20% or more. Special attention should be given to this.
  • ⚠️: Size increased in acceptable range (lower than 20%).
  • ✅: No change or even downsized.
  • 🗑️: The out file is deleted: not found in base branch.
  • 🆕: The out file is newly found: will be added to base branch.

@AlessioGr AlessioGr marked this pull request as ready for review June 22, 2026 07:42
relationTo: TCollectionSlug
/** Either the document ID or the full populated document. */
value: DataFromCollectionSlug<TCollectionSlug> | number | string
value: DataFromCollectionSlug<TCollectionSlug> | IDTypeForCollectionSlug<TCollectionSlug>

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically a separate change. number | string was inaccurate - we should be using the new IDTypeForCollectionSlug helper which reads the id type from the generated types.

Comment thread test/types/types.spec.ts
},
}),
).type.not.toRaiseError()
expect(payload.update).type.toBeCallableWith({

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just addressing tstyche deprecation warnings. toRaiseError is deprecated

@AlessioGr AlessioGr enabled auto-merge (squash) June 22, 2026 15:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant