);
From 7843e5485d37a888e289e9effbf1ab23b5279745 Mon Sep 17 00:00:00 2001
From: tobias-tengler <45513122+tobias-tengler@users.noreply.github.com>
Date: Wed, 1 Jul 2026 09:33:07 +0200
Subject: [PATCH 3/5] Improve documentation page titles
---
website/content/docs/fusion/index.md | 2 +-
.../content/docs/hotchocolate/fetching-data/batching/index.md | 2 +-
website/content/docs/hotchocolate/fetching-data/index.md | 2 +-
.../docs/hotchocolate/fetching-data/integrations/index.md | 2 +-
website/content/docs/hotchocolate/index.md | 2 +-
website/content/docs/hotchocolate/performance/index.md | 2 +-
website/content/docs/hotchocolate/resolvers/index.md | 2 +-
website/content/docs/hotchocolate/security/index.md | 2 +-
website/content/docs/hotchocolate/server/index.md | 2 +-
website/content/docs/mocha/index.md | 2 +-
website/content/docs/mocha/mediator/index.md | 2 +-
website/content/docs/nitro/index.md | 4 +---
website/content/docs/skillz/index.md | 2 +-
website/content/docs/strawberryshake/index.md | 2 +-
14 files changed, 14 insertions(+), 16 deletions(-)
diff --git a/website/content/docs/fusion/index.md b/website/content/docs/fusion/index.md
index 4ce5b451869..8a1d93bb54b 100644
--- a/website/content/docs/fusion/index.md
+++ b/website/content/docs/fusion/index.md
@@ -1,5 +1,5 @@
---
-title: "Introduction"
+title: Fusion
description: "Fusion is ChilliCream's GraphQL gateway for composing multiple services into one API, implementing the GraphQL Composite Schemas spec with build-time validation."
---
diff --git a/website/content/docs/hotchocolate/fetching-data/batching/index.md b/website/content/docs/hotchocolate/fetching-data/batching/index.md
index 2d5dc7e1b1a..94ee9bf2e25 100644
--- a/website/content/docs/hotchocolate/fetching-data/batching/index.md
+++ b/website/content/docs/hotchocolate/fetching-data/batching/index.md
@@ -1,5 +1,5 @@
---
-title: Overview
+title: Batching
description: "Overview of batching in Hot Chocolate: DataLoaders and batch resolvers group per-object data fetches into single queries to solve the N+1 problem."
---
diff --git a/website/content/docs/hotchocolate/fetching-data/index.md b/website/content/docs/hotchocolate/fetching-data/index.md
index 2eb93e26b00..1cff8760a6f 100644
--- a/website/content/docs/hotchocolate/fetching-data/index.md
+++ b/website/content/docs/hotchocolate/fetching-data/index.md
@@ -1,5 +1,5 @@
---
-title: Overview
+title: Fetching Data
description: "Overview of data middleware in Hot Chocolate: pagination, filtering, sorting, projections, and DataLoader batching applied to IQueryable data sources."
---
diff --git a/website/content/docs/hotchocolate/fetching-data/integrations/index.md b/website/content/docs/hotchocolate/fetching-data/integrations/index.md
index 6dc99681b36..110173cb2c4 100644
--- a/website/content/docs/hotchocolate/fetching-data/integrations/index.md
+++ b/website/content/docs/hotchocolate/fetching-data/integrations/index.md
@@ -1,5 +1,5 @@
---
-title: Executable
+title: Integrations
description: Learn how to use the IExecutable interface to abstract data sources in Hot Chocolate.
---
diff --git a/website/content/docs/hotchocolate/index.md b/website/content/docs/hotchocolate/index.md
index efbad9581e7..a811ac8edd8 100644
--- a/website/content/docs/hotchocolate/index.md
+++ b/website/content/docs/hotchocolate/index.md
@@ -1,5 +1,5 @@
---
-title: "Introduction"
+title: Hot Chocolate
description: "Hot Chocolate is an open-source GraphQL server for .NET that turns your C# classes into a spec-compliant schema and handles parsing, validation, and execution."
---
diff --git a/website/content/docs/hotchocolate/performance/index.md b/website/content/docs/hotchocolate/performance/index.md
index 3af8b187aa9..2e7b762b8b0 100644
--- a/website/content/docs/hotchocolate/performance/index.md
+++ b/website/content/docs/hotchocolate/performance/index.md
@@ -1,5 +1,5 @@
---
-title: "Overview"
+title: Performance
description: "Overview of Hot Chocolate performance features: faster startup, trusted documents, and persisted operations that cut parsing and validation overhead per request."
---
diff --git a/website/content/docs/hotchocolate/resolvers/index.md b/website/content/docs/hotchocolate/resolvers/index.md
index 5ca9265e641..16d2ba36b06 100644
--- a/website/content/docs/hotchocolate/resolvers/index.md
+++ b/website/content/docs/hotchocolate/resolvers/index.md
@@ -1,5 +1,5 @@
---
-title: Introduction
+title: Resolvers
description: "Introduction to resolvers in Hot Chocolate: how the resolver tree executes a query, defining resolver methods, accessing arguments, and injecting services."
---
diff --git a/website/content/docs/hotchocolate/security/index.md b/website/content/docs/hotchocolate/security/index.md
index 6cb463f7c56..119f1d45a78 100644
--- a/website/content/docs/hotchocolate/security/index.md
+++ b/website/content/docs/hotchocolate/security/index.md
@@ -1,5 +1,5 @@
---
-title: "Overview"
+title: Securing Your API
description: "Overview of securing a Hot Chocolate GraphQL API: cost analysis for public APIs, trusted documents for private ones, plus authorization and request limits."
---
diff --git a/website/content/docs/hotchocolate/server/index.md b/website/content/docs/hotchocolate/server/index.md
index d6ec3215f1a..c99cd231c35 100644
--- a/website/content/docs/hotchocolate/server/index.md
+++ b/website/content/docs/hotchocolate/server/index.md
@@ -1,5 +1,5 @@
---
-title: Overview
+title: Server
description: "Overview of configuring and operating a Hot Chocolate GraphQL server: endpoints, HTTP transport, interceptors, dependency injection, and instrumentation."
---
diff --git a/website/content/docs/mocha/index.md b/website/content/docs/mocha/index.md
index 2bf8f101d44..9fcbb3d3293 100644
--- a/website/content/docs/mocha/index.md
+++ b/website/content/docs/mocha/index.md
@@ -1,5 +1,5 @@
---
-title: "Introduction"
+title: Mocha
description: "Mocha is a messaging framework for .NET with a message bus for inter-service communication and a source-generated mediator for in-process CQRS."
---
diff --git a/website/content/docs/mocha/mediator/index.md b/website/content/docs/mocha/mediator/index.md
index 05edac546a4..687f746b81c 100644
--- a/website/content/docs/mocha/mediator/index.md
+++ b/website/content/docs/mocha/mediator/index.md
@@ -1,5 +1,5 @@
---
-title: "Overview"
+title: Mediator
description: "Use the Mocha Mediator to dispatch commands, queries, and notifications within a single process using zero-reflection, source-generated dispatch."
---
diff --git a/website/content/docs/nitro/index.md b/website/content/docs/nitro/index.md
index 5abf44c6881..7c2aedb1427 100644
--- a/website/content/docs/nitro/index.md
+++ b/website/content/docs/nitro/index.md
@@ -1,10 +1,8 @@
---
-title: "Introduction"
+title: Nitro
description: "Introduction to Nitro, the GraphQL IDE from ChilliCream with team collaboration, schema and client registries, and OpenTelemetry monitoring for your APIs."
---
-> Explore, engage and share your thoughts via [slack](http://slack.chillicream.com/) in the **#nitro** channel.
-
Nitro is a tool for developers, simplifying API creation, debugging, and collaboration. It enables effortless execution of GraphQL queries and mutations, with visual schema exploration. The platform emphasizes collaboration through seamless team sharing and synchronization. Nitro supports you during the entire API lifecycle with features like the schema and client registry for confident API evolution.
Are you hungry yet? [Let's get started!](./getting-started.md)
diff --git a/website/content/docs/skillz/index.md b/website/content/docs/skillz/index.md
index 1203e172b6e..9838e144b23 100644
--- a/website/content/docs/skillz/index.md
+++ b/website/content/docs/skillz/index.md
@@ -1,5 +1,5 @@
---
-title: "Introduction"
+title: Skillz
description: "skillz is a .NET CLI that installs, updates, and authors Agent Skills: portable SKILL.md files you can share across Claude Code, Cursor, and 50+ agents."
---
diff --git a/website/content/docs/strawberryshake/index.md b/website/content/docs/strawberryshake/index.md
index 8292f7c52af..f55b2da27ac 100644
--- a/website/content/docs/strawberryshake/index.md
+++ b/website/content/docs/strawberryshake/index.md
@@ -1,5 +1,5 @@
---
-title: Introduction
+title: Strawberry Shake
description: A reactive GraphQL client for .NET.
---
From 4aa045d4bb1891e1aba3682bcea8269c6ac2dd36 Mon Sep 17 00:00:00 2001
From: tobias-tengler <45513122+tobias-tengler@users.noreply.github.com>
Date: Wed, 1 Jul 2026 09:41:05 +0200
Subject: [PATCH 4/5] Improve root product doc page titles
---
website/app/docs/[...slug]/page.tsx | 9 ++++++---
website/content/docs/fusion/index.md | 1 +
website/content/docs/hotchocolate/index.md | 1 +
website/content/docs/mocha/index.md | 1 +
website/content/docs/nitro/index.md | 1 +
website/content/docs/skillz/index.md | 1 +
website/content/docs/strawberryshake/index.md | 1 +
website/src/helpers/readFrontmatter.ts | 6 ++++++
8 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/website/app/docs/[...slug]/page.tsx b/website/app/docs/[...slug]/page.tsx
index 9a6745f5d16..9b1ca15a349 100644
--- a/website/app/docs/[...slug]/page.tsx
+++ b/website/app/docs/[...slug]/page.tsx
@@ -72,7 +72,7 @@ export async function generateMetadata({
if (rel === null) {
return {};
}
- const { title, description, tags } = readFrontmatter(
+ const { title, metaTitle, description, tags } = readFrontmatter(
path.join(CONTENT_ROOT, rel),
);
const docTags = Array.isArray(tags)
@@ -82,10 +82,13 @@ export async function generateMetadata({
// Surface the product in the title tag ("OpenAPI Adapter - Hot Chocolate"),
// since searches almost always include the product name. Skip the suffix on
- // product index pages, where the title already is the product name.
+ // product index pages, where the title already is the product name. A page
+ // may set `metaTitle` to override the tag verbatim (no product suffix) while
+ // keeping a terse on-page heading.
const product = docBreadcrumbs(slug.slice(0, 1))[0]?.name;
const pageTitle =
- title && product && title !== product ? `${title} - ${product}` : title;
+ metaTitle ??
+ (title && product && title !== product ? `${title} - ${product}` : title);
const canonical = `/docs/${slug.join("/")}`;
diff --git a/website/content/docs/fusion/index.md b/website/content/docs/fusion/index.md
index 8a1d93bb54b..25741ab2774 100644
--- a/website/content/docs/fusion/index.md
+++ b/website/content/docs/fusion/index.md
@@ -1,5 +1,6 @@
---
title: Fusion
+metaTitle: "Fusion: Federated GraphQL Gateway"
description: "Fusion is ChilliCream's GraphQL gateway for composing multiple services into one API, implementing the GraphQL Composite Schemas spec with build-time validation."
---
diff --git a/website/content/docs/hotchocolate/index.md b/website/content/docs/hotchocolate/index.md
index a811ac8edd8..235a1cd4e5d 100644
--- a/website/content/docs/hotchocolate/index.md
+++ b/website/content/docs/hotchocolate/index.md
@@ -1,5 +1,6 @@
---
title: Hot Chocolate
+metaTitle: "Hot Chocolate: GraphQL Server for .NET"
description: "Hot Chocolate is an open-source GraphQL server for .NET that turns your C# classes into a spec-compliant schema and handles parsing, validation, and execution."
---
diff --git a/website/content/docs/mocha/index.md b/website/content/docs/mocha/index.md
index 9fcbb3d3293..ad83eabc554 100644
--- a/website/content/docs/mocha/index.md
+++ b/website/content/docs/mocha/index.md
@@ -1,5 +1,6 @@
---
title: Mocha
+metaTitle: "Mocha: Messaging Bus for .NET"
description: "Mocha is a messaging framework for .NET with a message bus for inter-service communication and a source-generated mediator for in-process CQRS."
---
diff --git a/website/content/docs/nitro/index.md b/website/content/docs/nitro/index.md
index 7c2aedb1427..72566122789 100644
--- a/website/content/docs/nitro/index.md
+++ b/website/content/docs/nitro/index.md
@@ -1,5 +1,6 @@
---
title: Nitro
+metaTitle: "Nitro: Observability and Governance for APIs"
description: "Introduction to Nitro, the GraphQL IDE from ChilliCream with team collaboration, schema and client registries, and OpenTelemetry monitoring for your APIs."
---
diff --git a/website/content/docs/skillz/index.md b/website/content/docs/skillz/index.md
index 9838e144b23..7dfc437e30d 100644
--- a/website/content/docs/skillz/index.md
+++ b/website/content/docs/skillz/index.md
@@ -1,5 +1,6 @@
---
title: Skillz
+metaTitle: "Skillz: Agent Skills CLI for .NET"
description: "skillz is a .NET CLI that installs, updates, and authors Agent Skills: portable SKILL.md files you can share across Claude Code, Cursor, and 50+ agents."
---
diff --git a/website/content/docs/strawberryshake/index.md b/website/content/docs/strawberryshake/index.md
index f55b2da27ac..e54a686edda 100644
--- a/website/content/docs/strawberryshake/index.md
+++ b/website/content/docs/strawberryshake/index.md
@@ -1,5 +1,6 @@
---
title: Strawberry Shake
+metaTitle: "Strawberry Shake: GraphQL Client for .NET"
description: A reactive GraphQL client for .NET.
---
diff --git a/website/src/helpers/readFrontmatter.ts b/website/src/helpers/readFrontmatter.ts
index 1bb45a235ae..d1774932fe8 100644
--- a/website/src/helpers/readFrontmatter.ts
+++ b/website/src/helpers/readFrontmatter.ts
@@ -3,6 +3,12 @@ import matter from "gray-matter";
export type DocFrontmatter = {
title?: string;
+ /**
+ * Overrides the browser tab / SEO `` (and Open Graph title) without
+ * changing the on-page `
`, which still uses `title`. Use for terse
+ * headings that need a richer, keyword-bearing title tag.
+ */
+ metaTitle?: string;
description?: string;
[key: string]: unknown;
};
From 14dfa9d6c46e991f58501784608f4ad02495f596 Mon Sep 17 00:00:00 2001
From: tobias-tengler <45513122+tobias-tengler@users.noreply.github.com>
Date: Wed, 1 Jul 2026 09:50:24 +0200
Subject: [PATCH 5/5] Sync missing content
---
website/content/docs/fusion/composition.md | 138 ++++++-------
.../fusion/data-requirements-and-mapping.md | 18 ++
.../docs/fusion/directives-reference.md | 8 +-
.../docs/fusion/entities-and-lookups.md | 2 +
.../defining-a-schema/directives.md | 184 ++++++++++++++++++
.../defining-a-schema/versioning.md | 10 +-
website/content/docs/mocha/sagas.md | 30 +--
7 files changed, 298 insertions(+), 92 deletions(-)
diff --git a/website/content/docs/fusion/composition.md b/website/content/docs/fusion/composition.md
index 96b0b208a3b..6a00c8756c7 100644
--- a/website/content/docs/fusion/composition.md
+++ b/website/content/docs/fusion/composition.md
@@ -78,7 +78,7 @@ Performs reachability analysis. Starting from the root types, the pipeline walks
A few rules account for most composition failures. Knowing the shape of the error helps you spot the cause quickly.
-**Two source schemas return different types for the same field.** If `Product.price` is `Float` in one source schema and `Int` in another, composition fails with `OUTPUT_FIELD_TYPES_NOT_MERGEABLE`. Align the types in the source schemas.
+**Two source schemas return incompatible types for the same field.** If `Product.price` is `Float` in one source schema and `Int` in another, composition fails with `OUTPUT_FIELD_TYPES_NOT_MERGEABLE`. Scalar and enum return types must match exactly, while object, interface, and union types merge when one declared type is a supertype of the others (for example, `Product` and a `union FeaturedItem = Product` merge to `FeaturedItem`). Align the types when no common supertype exists.
**A field is defined in multiple source schemas without `@shareable`.** Defining `User.name` in both Accounts and Reviews without marking it `@shareable` produces `INVALID_FIELD_SHARING`.
@@ -116,74 +116,74 @@ The placeholders `{0}`, `{1}`, etc. in the message column are replaced with the
## Errors
-| Code | Message | How to resolve |
-| ------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `CONFLICTING_SOURCE_SCHEMA_NAME` | '\{0\}' conflicts with the existing source schema name '\{1\}'. Either rename '\{0\}' to '\{1\}' if they're the same, or rename '\{0\}' to something else if they're different. | Two source schemas were registered under names that the composition treats as the same identity. Rename one of them in your composition configuration so each source schema has a unique name. |
-| [DISALLOWED_INACCESSIBLE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Disallowed-Inaccessible-Elements) | (Message varies by element kind: built-in scalar, introspection type, introspection field, introspection argument, or built-in directive argument.) | Built-in scalars, introspection types and their members, and built-in directive arguments cannot be marked `@inaccessible`. Remove the directive from the offending element in the named source schema. |
-| [EMPTY_MERGED_ENUM_TYPE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Empty-Merged-Enum-Type) | The merged enum type '\{0\}' is empty. | Every value of the enum was excluded by `@inaccessible` or tag filters, leaving nothing to merge. Either expose at least one enum value or remove the type entirely. |
-| [EMPTY_MERGED_INPUT_OBJECT_TYPE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Empty-Merged-Input-Object-Type) | The merged input object type '\{0\}' is empty. | All fields of the input type were excluded after merging. Expose at least one input field or remove the input type from your source schemas. |
-| [EMPTY_MERGED_INTERFACE_TYPE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Empty-Merged-Interface-Type) | The merged interface type '\{0\}' is empty. | All fields of the interface were filtered out by `@inaccessible` or tag exclusions. Expose at least one field on the interface, remove the filters that hide them, or drop the interface from the schema. |
-| [EMPTY_MERGED_OBJECT_TYPE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Empty-Merged-Object-Type) | The merged object type '\{0\}' is empty. | Every field on the object type was excluded. Expose at least one field, or remove the type if it is no longer needed. |
-| [EMPTY_MERGED_UNION_TYPE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Empty-Merged-Union-Type) | The merged union type '\{0\}' is empty. | All members of the union were excluded by `@inaccessible` or tag exclusions. Expose at least one member type, remove the filters that hide them, or remove the union. |
-| [ENUM_TYPE_DEFAULT_VALUE_INACCESSIBLE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Enum-Type-Default-Value-Inaccessible) | The default value of '\{0\}' references the inaccessible enum value '\{1\}'. | A default points to an enum value that is hidden from the composed schema. Either change the default to a value that is accessible or remove `@inaccessible` from the referenced enum value. |
-| [ENUM_VALUES_MISMATCH](https://graphql.github.io/composite-schemas-spec/draft/#sec-Enum-Values-Mismatch) | The enum type '\{0\}' in schema '\{1\}' must define the value '\{2\}'. | An enum is defined in more than one source schema and one of them is missing a value the others declare. Add the missing value to the named source schema so all definitions agree. |
-| [EXTERNAL_ARGUMENT_DEFAULT_MISMATCH](https://graphql.github.io/composite-schemas-spec/draft/#sec-External-Argument-Default-Mismatch) | The default value '\{0\}' of external argument '\{1\}' in schema '\{2\}' differs from the default value of '\{3\}' in schema '\{4\}'. | The same argument has different defaults in the external definition and the owning source schema. Align the default values across both source schemas. |
-| [EXTERNAL_ARGUMENT_MISSING](https://graphql.github.io/composite-schemas-spec/draft/#sec-External-Argument-Missing) | The external field '\{0\}' in schema '\{1\}' must define the argument '\{2\}'. | An `@external` field declaration is missing an argument that exists on the canonical definition. Add the argument to the external declaration with a matching type. |
-| [EXTERNAL_ARGUMENT_TYPE_MISMATCH](https://graphql.github.io/composite-schemas-spec/draft/#sec-External-Argument-Type-Mismatch) | The argument '\{0\}' on external field '\{1\}' in schema '\{2\}' has a different type (\{3\}) than it does in schema '\{4\}' (\{5\}). | The argument types of an `@external` declaration and the owning source schema disagree. Change the argument type in one of the source schemas so the signatures match exactly, including nullability. |
-| [EXTERNAL_MISSING_ON_BASE](https://graphql.github.io/composite-schemas-spec/draft/#sec-External-Missing-on-Base) | The external field '\{0\}' in schema '\{1\}' is not defined (non-external) in any other schema. | A field marked `@external` has no non-external definition anywhere. Add the canonical definition in another source schema, or remove `@external` if this source schema is meant to own the field. See [Field Ownership](./field-ownership-and-sharing.md). |
-| [EXTERNAL_ON_INTERFACE](https://graphql.github.io/composite-schemas-spec/draft/#sec-External-on-Interface) | The interface field '\{0\}' in schema '\{1\}' must not be marked as external. | `@external` is not valid on interface fields. Remove `@external` from the interface field; if you need to mark concrete implementations as external, place the directive on the implementing object types instead. |
-| [EXTERNAL_OVERRIDE_COLLISION](https://graphql.github.io/composite-schemas-spec/draft/#sec-External-Override-Collision) | The external field '\{0\}' in schema '\{1\}' must not be annotated with the @override directive. | A field cannot be both `@external` and `@override`. Decide which source schema owns the field and apply only the appropriate directive. |
-| [EXTERNAL_PROVIDES_COLLISION](https://graphql.github.io/composite-schemas-spec/draft/#sec-External-Provides-Collision) | The external field '\{0\}' in schema '\{1\}' must not be annotated with the @provides directive. | `@external` declares a field as not owned here, while `@provides` declares it as supplied here. Remove one of the directives so the ownership story is unambiguous. |
-| [EXTERNAL_REQUIRE_COLLISION](https://graphql.github.io/composite-schemas-spec/draft/#sec-External-Require-Collision) | The external field '\{0\}' in schema '\{1\}' must not have arguments that are annotated with the @require directive. | An `@external` field cannot consume `@require` arguments because it is not actually executed in this subgraph. Remove `@require` from the arguments, or move the field to a source schema where it is owned. |
-| [EXTERNAL_TYPE_MISMATCH](https://graphql.github.io/composite-schemas-spec/draft/#sec-External-Type-Mismatch) | The external field '\{0\}' in schema '\{1\}' has a different type (\{2\}) than it does in schema '\{3\}' (\{4\}). | The return type of the `@external` declaration differs from the canonical definition. Align the field type and nullability in both source schemas. |
-| [EXTERNAL_UNUSED](https://graphql.github.io/composite-schemas-spec/draft/#sec-External-Unused) | The external field '\{0\}' in schema '\{1\}' is not referenced by a @provides directive in the schema. | An `@external` field is declared but no `@provides` in this schema references it. Remove the unused declaration, or add a `@provides` that references the field. See [Field Ownership](./field-ownership-and-sharing.md). |
-| `FEDERATION_DIRECTIVE_NOT_SUPPORTED` | The @\{0\} directive is not supported. | The schema uses an Apollo Federation directive that Fusion does not support. Remove the directive or replace it with the equivalent Fusion construct. |
-| `FEDERATION_V1_NOT_SUPPORTED` | Federation v1 is not supported. | Upgrade the source schema to Federation v2 (or to native Fusion directives) before running composition. |
-| [FIELD_ARGUMENT_TYPES_NOT_MERGEABLE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Field-Argument-Types-Mergeable) | The argument '\{0\}' has a different type shape in schema '\{1\}' than it does in schema '\{2\}'. | The argument has a fundamentally different type (different named type or different list/non-null structure) across source schemas. Pick one canonical type and update the other source schema to match. |
-| [FIELD_WITH_MISSING_REQUIRED_ARGUMENT](https://graphql.github.io/composite-schemas-spec/draft/#sec-Field-With-Missing-Required-Arguments) | The argument '\{0\}' must be defined as required in schema '\{1\}'. Arguments marked with @require are treated as non-required. | The argument is required in some source schemas and optional or `@require`-driven in another. Mark the argument as required in the named source schema, or align all source schemas on the same nullability. |
-| [IMPLEMENTED_BY_INACCESSIBLE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Implemented-by-Inaccessible) | The field '\{0\}' implementing interface field '\{1\}' is inaccessible in the composed schema. | An object type implements an interface field, but its implementation is hidden. Either expose the implementing field or hide the interface field as well. |
-| [INPUT_FIELD_DEFAULT_MISMATCH](https://graphql.github.io/composite-schemas-spec/draft/#sec-Input-Field-Default-Mismatch) | The default value '\{0\}' of input field '\{1\}' in schema '\{2\}' differs from the default value of '\{3\}' in schema '\{4\}'. | The same input field has different defaults in two source schemas. Align the default value across all definitions of the input type. |
-| [INPUT_FIELD_TYPES_NOT_MERGEABLE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Input-Field-Types-mergeable) | The input field '\{0\}' has a different type shape in schema '\{1\}' than it does in schema '\{2\}'. | An input field has a different type structure (named type, list, or nullability) across source schemas. Decide on the canonical type and update the other source schema. |
-| [INPUT_WITH_MISSING_REQUIRED_FIELDS](https://graphql.github.io/composite-schemas-spec/draft/#sec-Input-With-Missing-Required-Fields) | The input type '\{0\}' in schema '\{1\}' must define the required field '\{2\}'. | One source schema requires a field on an input type that another source schema omits. Add the field (with the same type) to the named source schema so the input shape is consistent. |
-| `INPUT_WITH_MISSING_ONEOF` | The input type '\{0\}' in schema '\{1\}' must be annotated with the '@oneOf' directive, since the same type has been annotated with it in schema '\{2\}'. | The same input type is `@oneOf` in one source schema but not in another. Add `@oneOf` to the input type in the named source schema (or remove it from the other) so all definitions agree. |
-| [INTERFACE_FIELD_NO_IMPLEMENTATION](https://graphql.github.io/composite-schemas-spec/draft/#sec-Interface-Field-No-Implementation) | The merged object type '\{0\}' must implement the field '\{1\}' on interface '\{2\}'. | After merging, an object type declares it implements the interface but does not provide every field the interface requires. Add the missing field to the object type, or stop implementing the interface. |
-| [INVALID_FIELD_SHARING](https://graphql.github.io/composite-schemas-spec/draft/#sec-Invalid-Field-Sharing) | The field '\{0\}' in schema '\{1\}' must be shareable. | The same non-key field is owned by more than one source schema without an explicit sharing contract. Add `@shareable` to the field (or to the enclosing type, which applies to all of its fields) in every source schema that defines it, or move ownership to a single source schema. See [Field Ownership](./field-ownership-and-sharing.md). |
-| [INVALID_GRAPHQL](https://graphql.github.io/composite-schemas-spec/draft/#sec-Invalid-GraphQL) | Invalid GraphQL in source schema. Exception message: \{0\}. | The source schema does not parse as valid GraphQL. Read the included parser exception, fix the SDL in the offending source schema, and re-export. See [Getting Started](./getting-started.md) for how to export a source schema. |
-| [INVALID_SHAREABLE_USAGE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Invalid-Shareable-Usage) | The field '\{0\}' in schema '\{1\}' must not be marked as shareable. | `@shareable` was applied where it is not allowed (for example, on a field that is already governed by another ownership directive). Remove `@shareable` from the field. See [Field Ownership](./field-ownership-and-sharing.md). |
-| [IS_INVALID_FIELDS](https://graphql.github.io/composite-schemas-spec/draft/#sec-Is-Invalid-Fields) | The @is directive on argument '\{0\}' in schema '\{1\}' specifies an invalid field selection against the composed schema. | The field selection map in `@is(field: ...)` does not resolve against the entity's fields. Update it to reference fields that actually exist on the parent type. See [Entities and Lookups](./entities-and-lookups.md). |
-| [IS_INVALID_FIELD_TYPE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Is-Invalid-Field-Type) | The @is directive on argument '\{0\}' in schema '\{1\}' must specify a string value for the 'field' argument. | The `field` argument was given as a non-string literal. Pass it as a quoted string, for example `@is(field: "id")`. |
-| [IS_INVALID_SYNTAX](https://graphql.github.io/composite-schemas-spec/draft/#sec-Is-Invalid-Syntax) | The @is directive on argument '\{0\}' in schema '\{1\}' contains invalid syntax in the 'field' argument. | The string value for `field` is not a valid field selection map. Rewrite it as a syntactically valid field selection map. |
-| [IS_INVALID_USAGE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Is-Invalid-Usage) | The @is directive on argument '\{0\}' in schema '\{1\}' is invalid because the declaring field is not a lookup field. | `@is` is only valid on arguments of lookup fields. Move `@is` to a lookup, or annotate the declaring field with `@lookup`. See [Entities and Lookups](./entities-and-lookups.md). |
-| [KEY_DIRECTIVE_IN_FIELDS_ARGUMENT](https://graphql.github.io/composite-schemas-spec/draft/#sec-Key-Directive-in-Fields-Argument) | A @key directive on type '\{0\}' in schema '\{1\}' references field '\{2\}', which must not include directive applications. | The `fields` selection of `@key` cannot apply directives to the selected fields. Remove the directive applications from the selection set. See [Entities and Lookups](./entities-and-lookups.md). |
-| [KEY_FIELDS_HAS_ARGUMENTS](https://graphql.github.io/composite-schemas-spec/draft/#sec-Key-Fields-Has-Arguments) | A @key directive on type '\{0\}' in schema '\{1\}' references field '\{2\}', which must not have arguments. | A field referenced by `@key` is being called with arguments, which is not allowed for key fields. Either select an argument-less field or expose a derived argument-less field for use as a key. |
-| [KEY_FIELDS_SELECT_INVALID_TYPE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Key-Fields-Select-Invalid-Type) | A @key directive on type '\{0\}' in schema '\{1\}' references field '\{2\}', which must not be a list, interface, or union type. | Key fields must resolve to scalar, enum, or object types, not lists, interfaces, or unions. Pick a different field for the key, or model the key as a scalar identifier. |
-| [KEY_INVALID_FIELDS](https://graphql.github.io/composite-schemas-spec/draft/#sec-Key-Invalid-Fields) | A @key directive on type '\{0\}' in schema '\{1\}' specifies an invalid field selection against the composed schema. | The `fields` selection refers to fields that do not exist on the type. Add the missing fields to the type or correct the selection set. See [Entities and Lookups](./entities-and-lookups.md). |
-| [KEY_INVALID_FIELDS_TYPE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Key-Invalid-Fields-Type) | A @key directive on type '\{0\}' in schema '\{1\}' must specify a string value for the 'fields' argument. | The `fields` argument was given as a non-string literal. Pass it as a quoted string, for example `@key(fields: "id")`. |
-| [KEY_INVALID_SYNTAX](https://graphql.github.io/composite-schemas-spec/draft/#sec-Key-Invalid-Syntax) | A @key directive on type '\{0\}' in schema '\{1\}' contains invalid syntax in the 'fields' argument. | The string value for `fields` is not a valid GraphQL selection set. Rewrite it as a syntactically valid selection. |
-| [LOOKUP_RETURNS_LIST](https://graphql.github.io/composite-schemas-spec/draft/#sec-Lookup-Returns-List) | The lookup field '\{0\}' in schema '\{1\}' must not return a list. | A `@lookup` field returned a list, which prevents the gateway from mapping a key to a single entity. Change the return type to a single nullable entity. See [Entities and Lookups](./entities-and-lookups.md). |
-| [NON_NULL_INPUT_FIELD_IS_INACCESSIBLE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Non-Null-Input-Fields-cannot-be-inaccessible) | The non-null input field '\{0\}' in schema '\{1\}' must be accessible in the composed schema. | A required input field was hidden by `@inaccessible`, which would make the input impossible to construct from the gateway. Either make the field nullable or expose it. |
-| [NO_QUERIES](https://graphql.github.io/composite-schemas-spec/draft/#sec-No-Queries) | The merged query type has no accessible fields. | After merging and applying accessibility filters, no query fields remain. Expose at least one query field, or remove `@inaccessible` from the queries you intend to publish. |
-| [OUTPUT_FIELD_TYPES_NOT_MERGEABLE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Output-Field-Types-Mergeable) | The output field '\{0\}' has a different type shape in schema '\{1\}' than it does in schema '\{2\}'. | Two source schemas return different types (different named type, different list shape, or different nullability) for the same field. Align the return types in both source schemas. |
-| [OVERRIDE_FROM_SELF](https://graphql.github.io/composite-schemas-spec/draft/#sec-Override-from-Self) | The @override directive on field '\{0\}' in schema '\{1\}' must not reference the same schema. | `@override(from: "...")` cannot point at the source schema that owns the directive. Set `from` to the name of the source schema the field is being taken from. See [Field Ownership](./field-ownership-and-sharing.md). |
-| [OVERRIDE_ON_INTERFACE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Override-on-Interface) | The interface field '\{0\}' in schema '\{1\}' must not be annotated with the @override directive. | `@override` cannot be applied to interface fields. Move the directive to the implementing object types if you need to take ownership of a specific implementation. See [Field Ownership](./field-ownership-and-sharing.md). |
-| [PROVIDES_DIRECTIVE_IN_FIELDS_ARGUMENT](https://graphql.github.io/composite-schemas-spec/draft/#sec-Provides-Directive-in-Fields-Argument) | The @provides directive on field '\{0\}' in schema '\{1\}' references field '\{2\}', which must not include directive applications. | The selection in `@provides(fields: ...)` cannot apply directives. Remove the directive applications from the selection. See [Field Ownership](./field-ownership-and-sharing.md). |
-| [PROVIDES_FIELDS_HAS_ARGUMENTS](https://graphql.github.io/composite-schemas-spec/draft/#sec-Provides-Fields-Has-Arguments) | The @provides directive on field '\{0\}' in schema '\{1\}' references field '\{2\}', which must not have arguments. | A field selected by `@provides` is being called with arguments, which is not allowed. Pick an argument-less field or restructure the schema so the provided field needs no arguments. |
-| [PROVIDES_FIELDS_MISSING_EXTERNAL](https://graphql.github.io/composite-schemas-spec/draft/#sec-Provides-Fields-Missing-External) | The @provides directive on field '\{0\}' in schema '\{1\}' references field '\{2\}', which must be marked as external. | `@provides` only makes sense when the referenced field is `@external` here. Add `@external` to the referenced field in the same source schema. See [Field Ownership](./field-ownership-and-sharing.md). |
-| [PROVIDES_INVALID_FIELDS](https://graphql.github.io/composite-schemas-spec/draft/#sec-Provides-Invalid-Fields) | The @provides directive on field '\{0\}' in schema '\{1\}' specifies an invalid field selection. | The selection points to fields that do not exist on the returned type. Update the selection so it matches fields that the returned type actually defines. |
-| [PROVIDES_INVALID_FIELDS_TYPE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Provides-Invalid-Fields-Type) | The @provides directive on field '\{0\}' in schema '\{1\}' must specify a string value for the 'fields' argument. | The `fields` argument was given as a non-string literal. Pass it as a quoted string. |
-| [PROVIDES_INVALID_SYNTAX](https://graphql.github.io/composite-schemas-spec/draft/#sec-Provides-Invalid-Syntax) | The @provides directive on field '\{0\}' in schema '\{1\}' contains invalid syntax in the 'fields' argument. | The selection set syntax in `fields` is invalid. Rewrite it as a valid GraphQL selection set. |
-| [PROVIDES_ON_NON_COMPOSITE_FIELD](https://graphql.github.io/composite-schemas-spec/draft/#sec-Provides-on-Non-Composite-Field) | The field '\{0\}' in schema '\{1\}' includes a @provides directive, but does not return a composite type. | `@provides` only applies when a field returns an object, interface, or union, because the directive describes which sub-fields are also delivered. Remove `@provides`, or change the field to return a composite type. |
-| [QUERY_ROOT_TYPE_INACCESSIBLE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Query-Root-Type-Inaccessible) | The root query type in schema '\{0\}' must be accessible. | The query root cannot be marked `@inaccessible`. Remove the directive from the root query type. |
-| [REFERENCE_TO_INACCESSIBLE_TYPE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Reference-To-Inaccessible-Type) | (Message varies by reference site: field argument, input field, or output field.) | A publicly accessible position (a field argument, input field, or output field) references a type that has been hidden from the composed schema. Either expose the referenced type or change the position to use a publicly accessible type. |
-| [REFERENCE_TO_INTERNAL_TYPE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Reference-To-Internal-Type) | The merged field '\{0\}' in type '\{1\}' cannot reference the internal type '\{2\}'. | A public field returns an internal type, which would leak the internal type into the composed schema. Either mark the field as internal as well, or change the return type to a non-internal one. |
-| [REQUIRE_INVALID_FIELDS](https://graphql.github.io/composite-schemas-spec/draft/#sec-Require-Invalid-Fields) | The @require directive on argument '\{0\}' in schema '\{1\}' specifies an invalid field selection against the composed schema. | The field selection map in `@require(field: ...)` references fields that the parent type does not expose. Update it to reference fields that exist on the parent. See [Entities and Lookups](./entities-and-lookups.md). |
-| [REQUIRE_INVALID_FIELD_TYPE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Require-Invalid-Field-Type) | The @require directive on argument '\{0\}' in schema '\{1\}' must specify a string value for the 'field' argument. | The `field` argument must be a string literal. Pass it as a quoted string. |
-| [REQUIRE_INVALID_SYNTAX](https://graphql.github.io/composite-schemas-spec/draft/#sec-Require-Invalid-Syntax) | The @require directive on argument '\{0\}' in schema '\{1\}' contains invalid syntax in the 'field' argument. | The `field` value is not a valid field selection map. Rewrite it as a syntactically valid field selection map. |
-| [ROOT_MUTATION_USED](https://graphql.github.io/composite-schemas-spec/draft/#sec-Root-Mutation-Used) | The root mutation type in schema '\{0\}' must be named 'Mutation'. | Fusion requires the root mutation type to use the canonical name `Mutation`. Rename the type in the named source schema. A type named `Mutation` must not exist unless it is the root mutation type. |
-| [ROOT_QUERY_USED](https://graphql.github.io/composite-schemas-spec/draft/#sec-Root-Query-Used) | The root query type in schema '\{0\}' must be named 'Query'. | Fusion requires the root query type to use the canonical name `Query`. Rename the type in the named source schema. A type named `Query` must not exist unless it is the root query type. See [Getting Started](./getting-started.md) for the expected schema layout. |
-| [ROOT_SUBSCRIPTION_USED](https://graphql.github.io/composite-schemas-spec/draft/#sec-Root-Subscription-Used) | The root subscription type in schema '\{0\}' must be named 'Subscription'. | Fusion requires the root subscription type to use the canonical name `Subscription`. Rename the type in the named source schema. A type named `Subscription` must not exist unless it is the root subscription type. |
-| [TYPE_KIND_MISMATCH](https://graphql.github.io/composite-schemas-spec/draft/#sec-Type-Kind-Mismatch) | The type '\{0\}' has a different kind in schema '\{1\}' (\{2\}) than it does in schema '\{3\}' (\{4\}). | The same type name was used for different kinds (for example, an object in one source schema and an interface in another). Decide which kind is correct and update the other source schema, or rename one of the types so they no longer collide. |
-| [UNSATISFIABLE_QUERY_PATH](https://graphql.github.io/composite-schemas-spec/draft/#sec-Unsatisfiable-Query-Path) | (Message varies. Includes the unreachable field, the path the validator tried, and the lookups it considered.) | Some reachable field cannot be resolved through the available `@lookup` and `@key` paths. See [Diagnosing UNSATISFIABLE_QUERY_PATH Errors](#diagnosing-unsatisfiable_query_path-errors) for how to read the message and fix the underlying gap. |
+| Code | Message | How to resolve |
+| ------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `CONFLICTING_SOURCE_SCHEMA_NAME` | '\{0\}' conflicts with the existing source schema name '\{1\}'. Either rename '\{0\}' to '\{1\}' if they're the same, or rename '\{0\}' to something else if they're different. | Two source schemas were registered under names that the composition treats as the same identity. Rename one of them in your composition configuration so each source schema has a unique name. |
+| [DISALLOWED_INACCESSIBLE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Disallowed-Inaccessible-Elements) | (Message varies by element kind: built-in scalar, introspection type, introspection field, introspection argument, or built-in directive argument.) | Built-in scalars, introspection types and their members, and built-in directive arguments cannot be marked `@inaccessible`. Remove the directive from the offending element in the named source schema. |
+| [EMPTY_MERGED_ENUM_TYPE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Empty-Merged-Enum-Type) | The merged enum type '\{0\}' is empty. | Every value of the enum was excluded by `@inaccessible` or tag filters, leaving nothing to merge. Either expose at least one enum value or remove the type entirely. |
+| [EMPTY_MERGED_INPUT_OBJECT_TYPE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Empty-Merged-Input-Object-Type) | The merged input object type '\{0\}' is empty. | All fields of the input type were excluded after merging. Expose at least one input field or remove the input type from your source schemas. |
+| [EMPTY_MERGED_INTERFACE_TYPE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Empty-Merged-Interface-Type) | The merged interface type '\{0\}' is empty. | All fields of the interface were filtered out by `@inaccessible` or tag exclusions. Expose at least one field on the interface, remove the filters that hide them, or drop the interface from the schema. |
+| [EMPTY_MERGED_OBJECT_TYPE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Empty-Merged-Object-Type) | The merged object type '\{0\}' is empty. | Every field on the object type was excluded. Expose at least one field, or remove the type if it is no longer needed. |
+| [EMPTY_MERGED_UNION_TYPE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Empty-Merged-Union-Type) | The merged union type '\{0\}' is empty. | All members of the union were excluded by `@inaccessible` or tag exclusions. Expose at least one member type, remove the filters that hide them, or remove the union. |
+| [ENUM_TYPE_DEFAULT_VALUE_INACCESSIBLE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Enum-Type-Default-Value-Inaccessible) | The default value of '\{0\}' references the inaccessible enum value '\{1\}'. | A default points to an enum value that is hidden from the composed schema. Either change the default to a value that is accessible or remove `@inaccessible` from the referenced enum value. |
+| [ENUM_VALUES_MISMATCH](https://graphql.github.io/composite-schemas-spec/draft/#sec-Enum-Values-Mismatch) | The enum type '\{0\}' in schema '\{1\}' must define the value '\{2\}'. | An enum is defined in more than one source schema and one of them is missing a value the others declare. Add the missing value to the named source schema so all definitions agree. |
+| [EXTERNAL_ARGUMENT_DEFAULT_MISMATCH](https://graphql.github.io/composite-schemas-spec/draft/#sec-External-Argument-Default-Mismatch) | The default value '\{0\}' of external argument '\{1\}' in schema '\{2\}' differs from the default value of '\{3\}' in schema '\{4\}'. | The same argument has different defaults in the external definition and the owning source schema. Align the default values across both source schemas. |
+| [EXTERNAL_ARGUMENT_MISSING](https://graphql.github.io/composite-schemas-spec/draft/#sec-External-Argument-Missing) | The external field '\{0\}' in schema '\{1\}' must define the argument '\{2\}'. | An `@external` field declaration is missing an argument that exists on the canonical definition. Add the argument to the external declaration with a matching type. |
+| [EXTERNAL_ARGUMENT_TYPE_MISMATCH](https://graphql.github.io/composite-schemas-spec/draft/#sec-External-Argument-Type-Mismatch) | The argument '\{0\}' on external field '\{1\}' in schema '\{2\}' has a different type (\{3\}) than it does in schema '\{4\}' (\{5\}). | The argument types of an `@external` declaration and the owning source schema disagree. Change the argument type in one of the source schemas so the signatures match exactly, including nullability. |
+| [EXTERNAL_MISSING_ON_BASE](https://graphql.github.io/composite-schemas-spec/draft/#sec-External-Missing-on-Base) | The external field '\{0\}' in schema '\{1\}' is not defined (non-external) in any other schema. | A field marked `@external` has no non-external definition anywhere. Add the canonical definition in another source schema, or remove `@external` if this source schema is meant to own the field. See [Field Ownership](./field-ownership-and-sharing.md). |
+| [EXTERNAL_ON_INTERFACE](https://graphql.github.io/composite-schemas-spec/draft/#sec-External-on-Interface) | The interface field '\{0\}' in schema '\{1\}' must not be marked as external. | `@external` is not valid on interface fields. Remove `@external` from the interface field; if you need to mark concrete implementations as external, place the directive on the implementing object types instead. |
+| [EXTERNAL_OVERRIDE_COLLISION](https://graphql.github.io/composite-schemas-spec/draft/#sec-External-Override-Collision) | The external field '\{0\}' in schema '\{1\}' must not be annotated with the @override directive. | A field cannot be both `@external` and `@override`. Decide which source schema owns the field and apply only the appropriate directive. |
+| [EXTERNAL_PROVIDES_COLLISION](https://graphql.github.io/composite-schemas-spec/draft/#sec-External-Provides-Collision) | The external field '\{0\}' in schema '\{1\}' must not be annotated with the @provides directive. | `@external` declares a field as not owned here, while `@provides` declares it as supplied here. Remove one of the directives so the ownership story is unambiguous. |
+| [EXTERNAL_REQUIRE_COLLISION](https://graphql.github.io/composite-schemas-spec/draft/#sec-External-Require-Collision) | The external field '\{0\}' in schema '\{1\}' must not have arguments that are annotated with the @require directive. | An `@external` field cannot consume `@require` arguments because it is not actually executed in this subgraph. Remove `@require` from the arguments, or move the field to a source schema where it is owned. |
+| [EXTERNAL_TYPE_MISMATCH](https://graphql.github.io/composite-schemas-spec/draft/#sec-External-Type-Mismatch) | The external field '\{0\}' in schema '\{1\}' has a different type (\{2\}) than it does in schema '\{3\}' (\{4\}). | The return type of the `@external` declaration differs from the canonical definition. Align the field type and nullability in both source schemas. |
+| [EXTERNAL_UNUSED](https://graphql.github.io/composite-schemas-spec/draft/#sec-External-Unused) | The external field '\{0\}' in schema '\{1\}' is not referenced by a @provides directive in the schema. | An `@external` field is declared but no `@provides` in this schema references it. Remove the unused declaration, or add a `@provides` that references the field. See [Field Ownership](./field-ownership-and-sharing.md). |
+| `FEDERATION_DIRECTIVE_NOT_SUPPORTED` | The @\{0\} directive is not supported. | The schema uses an Apollo Federation directive that Fusion does not support. Remove the directive or replace it with the equivalent Fusion construct. |
+| `FEDERATION_V1_NOT_SUPPORTED` | Federation v1 is not supported. | Upgrade the source schema to Federation v2 (or to native Fusion directives) before running composition. |
+| [FIELD_ARGUMENT_TYPES_NOT_MERGEABLE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Field-Argument-Types-Mergeable) | The argument '\{0\}' has a different type shape in schema '\{1\}' than it does in schema '\{2\}'. | The argument has a fundamentally different type (different named type or different list/non-null structure) across source schemas. Pick one canonical type and update the other source schema to match. |
+| [FIELD_WITH_MISSING_REQUIRED_ARGUMENT](https://graphql.github.io/composite-schemas-spec/draft/#sec-Field-With-Missing-Required-Arguments) | The argument '\{0\}' must be defined as required in schema '\{1\}'. Arguments marked with @require are treated as non-required. | The argument is required in some source schemas and optional or `@require`-driven in another. Mark the argument as required in the named source schema, or align all source schemas on the same nullability. |
+| [IMPLEMENTED_BY_INACCESSIBLE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Implemented-by-Inaccessible) | The field '\{0\}' implementing interface field '\{1\}' is inaccessible in the composed schema. | An object type implements an interface field, but its implementation is hidden. Either expose the implementing field or hide the interface field as well. |
+| [INPUT_FIELD_DEFAULT_MISMATCH](https://graphql.github.io/composite-schemas-spec/draft/#sec-Input-Field-Default-Mismatch) | The default value '\{0\}' of input field '\{1\}' in schema '\{2\}' differs from the default value of '\{3\}' in schema '\{4\}'. | The same input field has different defaults in two source schemas. Align the default value across all definitions of the input type. |
+| [INPUT_FIELD_TYPES_NOT_MERGEABLE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Input-Field-Types-mergeable) | The input field '\{0\}' has a different type shape in schema '\{1\}' than it does in schema '\{2\}'. | An input field has a different type structure (named type, list, or nullability) across source schemas. Decide on the canonical type and update the other source schema. |
+| [INPUT_WITH_MISSING_REQUIRED_FIELDS](https://graphql.github.io/composite-schemas-spec/draft/#sec-Input-With-Missing-Required-Fields) | The input type '\{0\}' in schema '\{1\}' must define the required field '\{2\}'. | One source schema requires a field on an input type that another source schema omits. Add the field (with the same type) to the named source schema so the input shape is consistent. |
+| `INPUT_WITH_MISSING_ONEOF` | The input type '\{0\}' in schema '\{1\}' must be annotated with the '@oneOf' directive, since the same type has been annotated with it in schema '\{2\}'. | The same input type is `@oneOf` in one source schema but not in another. Add `@oneOf` to the input type in the named source schema (or remove it from the other) so all definitions agree. |
+| [INTERFACE_FIELD_NO_IMPLEMENTATION](https://graphql.github.io/composite-schemas-spec/draft/#sec-Interface-Field-No-Implementation) | The merged object type '\{0\}' must implement the field '\{1\}' on interface '\{2\}'. | After merging, an object type declares it implements the interface but does not provide every field the interface requires. Add the missing field to the object type, or stop implementing the interface. |
+| [INVALID_FIELD_SHARING](https://graphql.github.io/composite-schemas-spec/draft/#sec-Invalid-Field-Sharing) | The field '\{0\}' in schema '\{1\}' must be shareable. | The same non-key field is owned by more than one source schema without an explicit sharing contract. Add `@shareable` to the field (or to the enclosing type, which applies to all of its fields) in every source schema that defines it, or move ownership to a single source schema. See [Field Ownership](./field-ownership-and-sharing.md). |
+| [INVALID_GRAPHQL](https://graphql.github.io/composite-schemas-spec/draft/#sec-Invalid-GraphQL) | Invalid GraphQL in source schema. Exception message: \{0\}. | The source schema does not parse as valid GraphQL. Read the included parser exception, fix the SDL in the offending source schema, and re-export. See [Getting Started](./getting-started.md) for how to export a source schema. |
+| [INVALID_SHAREABLE_USAGE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Invalid-Shareable-Usage) | The field '\{0\}' in schema '\{1\}' must not be marked as shareable. | `@shareable` was applied where it is not allowed (for example, on a field that is already governed by another ownership directive). Remove `@shareable` from the field. See [Field Ownership](./field-ownership-and-sharing.md). |
+| [IS_INVALID_FIELDS](https://graphql.github.io/composite-schemas-spec/draft/#sec-Is-Invalid-Fields) | The @is directive on argument '\{0\}' in schema '\{1\}' specifies an invalid field selection against the composed schema. | The field selection map in `@is(field: ...)` does not resolve against the entity's fields. Update it to reference fields that actually exist on the parent type. See [Entities and Lookups](./entities-and-lookups.md). |
+| [IS_INVALID_FIELD_TYPE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Is-Invalid-Field-Type) | The @is directive on argument '\{0\}' in schema '\{1\}' must specify a string value for the 'field' argument. | The `field` argument was given as a non-string literal. Pass it as a quoted string, for example `@is(field: "id")`. |
+| [IS_INVALID_SYNTAX](https://graphql.github.io/composite-schemas-spec/draft/#sec-Is-Invalid-Syntax) | The @is directive on argument '\{0\}' in schema '\{1\}' contains invalid syntax in the 'field' argument. | The string value for `field` is not a valid field selection map. Rewrite it as a syntactically valid field selection map. |
+| [IS_INVALID_USAGE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Is-Invalid-Usage) | The @is directive on argument '\{0\}' in schema '\{1\}' is invalid because the declaring field is not a lookup field. | `@is` is only valid on arguments of lookup fields. Move `@is` to a lookup, or annotate the declaring field with `@lookup`. See [Entities and Lookups](./entities-and-lookups.md). |
+| [KEY_DIRECTIVE_IN_FIELDS_ARGUMENT](https://graphql.github.io/composite-schemas-spec/draft/#sec-Key-Directive-in-Fields-Argument) | A @key directive on type '\{0\}' in schema '\{1\}' references field '\{2\}', which must not include directive applications. | The `fields` selection of `@key` cannot apply directives to the selected fields. Remove the directive applications from the selection set. See [Entities and Lookups](./entities-and-lookups.md). |
+| [KEY_FIELDS_SELECT_INVALID_TYPE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Key-Fields-Select-Invalid-Type) | A @key directive on type '\{0\}' in schema '\{1\}' references field '\{2\}', which must not be a list, interface, or union type. | Key fields must resolve to scalar, enum, or object types, not lists, interfaces, or unions. Pick a different field for the key, or model the key as a scalar identifier. |
+| [KEY_INVALID_ARGUMENTS](https://graphql.github.io/composite-schemas-spec/draft/#sec-Key-Invalid-Arguments) | A @key directive on type '\{0\}' in schema '\{1\}' specifies invalid arguments. \{2\} | Key fields support constant arguments. Remove or correct any argument that is unknown, has an incompatible value type, or leaves a required argument unsupplied. |
+| [KEY_INVALID_FIELDS](https://graphql.github.io/composite-schemas-spec/draft/#sec-Key-Invalid-Fields) | A @key directive on type '\{0\}' in schema '\{1\}' specifies an invalid field selection against the composed schema. | The `fields` selection refers to fields that do not exist on the type. Add the missing fields to the type or correct the selection set. See [Entities and Lookups](./entities-and-lookups.md). |
+| [KEY_INVALID_FIELDS_TYPE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Key-Invalid-Fields-Type) | A @key directive on type '\{0\}' in schema '\{1\}' must specify a string value for the 'fields' argument. | The `fields` argument was given as a non-string literal. Pass it as a quoted string, for example `@key(fields: "id")`. |
+| [KEY_INVALID_SYNTAX](https://graphql.github.io/composite-schemas-spec/draft/#sec-Key-Invalid-Syntax) | A @key directive on type '\{0\}' in schema '\{1\}' contains invalid syntax in the 'fields' argument. | The string value for `fields` is not a valid GraphQL selection set. Rewrite it as a syntactically valid selection. |
+| [LOOKUP_RETURNS_LIST](https://graphql.github.io/composite-schemas-spec/draft/#sec-Lookup-Returns-List) | The lookup field '\{0\}' in schema '\{1\}' must not return a list. | A `@lookup` field returned a list, which prevents the gateway from mapping a key to a single entity. Change the return type to a single nullable entity. See [Entities and Lookups](./entities-and-lookups.md). |
+| [NON_NULL_INPUT_FIELD_IS_INACCESSIBLE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Non-Null-Input-Fields-cannot-be-inaccessible) | The non-null input field '\{0\}' in schema '\{1\}' must be accessible in the composed schema. | A required input field was hidden by `@inaccessible`, which would make the input impossible to construct from the gateway. Either make the field nullable or expose it. |
+| [NO_QUERIES](https://graphql.github.io/composite-schemas-spec/draft/#sec-No-Queries) | The merged query type has no accessible fields. | After merging and applying accessibility filters, no query fields remain. Expose at least one query field, or remove `@inaccessible` from the queries you intend to publish. |
+| [OUTPUT_FIELD_TYPES_NOT_MERGEABLE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Output-Field-Types-Mergeable) | The output field '\{0\}' has a different type shape in schema '\{1\}' than it does in schema '\{2\}'. | The field's return type cannot be unified across source schemas: leaf types (scalar or enum) differ in name or kind, the list shape differs, or composite types (object, interface, or union) share no common supertype. Nullability differences and composite types with a common supertype merge automatically; otherwise align the return types. |
+| [OVERRIDE_FROM_SELF](https://graphql.github.io/composite-schemas-spec/draft/#sec-Override-from-Self) | The @override directive on field '\{0\}' in schema '\{1\}' must not reference the same schema. | `@override(from: "...")` cannot point at the source schema that owns the directive. Set `from` to the name of the source schema the field is being taken from. See [Field Ownership](./field-ownership-and-sharing.md). |
+| [OVERRIDE_ON_INTERFACE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Override-on-Interface) | The interface field '\{0\}' in schema '\{1\}' must not be annotated with the @override directive. | `@override` cannot be applied to interface fields. Move the directive to the implementing object types if you need to take ownership of a specific implementation. See [Field Ownership](./field-ownership-and-sharing.md). |
+| [PROVIDES_DIRECTIVE_IN_FIELDS_ARGUMENT](https://graphql.github.io/composite-schemas-spec/draft/#sec-Provides-Directive-in-Fields-Argument) | The @provides directive on field '\{0\}' in schema '\{1\}' references field '\{2\}', which must not include directive applications. | The selection in `@provides(fields: ...)` cannot apply directives. Remove the directive applications from the selection. See [Field Ownership](./field-ownership-and-sharing.md). |
+| [PROVIDES_FIELDS_HAS_ARGUMENTS](https://graphql.github.io/composite-schemas-spec/draft/#sec-Provides-Fields-Has-Arguments) | The @provides directive on field '\{0\}' in schema '\{1\}' references field '\{2\}', which must not have arguments. | A field selected by `@provides` is being called with arguments, which is not allowed. Pick an argument-less field or restructure the schema so the provided field needs no arguments. |
+| [PROVIDES_FIELDS_MISSING_EXTERNAL](https://graphql.github.io/composite-schemas-spec/draft/#sec-Provides-Fields-Missing-External) | The @provides directive on field '\{0\}' in schema '\{1\}' references field '\{2\}', which must be marked as external. | `@provides` only makes sense when the referenced field is `@external` here. Add `@external` to the referenced field in the same source schema. See [Field Ownership](./field-ownership-and-sharing.md). |
+| [PROVIDES_INVALID_FIELDS](https://graphql.github.io/composite-schemas-spec/draft/#sec-Provides-Invalid-Fields) | The @provides directive on field '\{0\}' in schema '\{1\}' specifies an invalid field selection. | The selection points to fields that do not exist on the returned type. Update the selection so it matches fields that the returned type actually defines. |
+| [PROVIDES_INVALID_FIELDS_TYPE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Provides-Invalid-Fields-Type) | The @provides directive on field '\{0\}' in schema '\{1\}' must specify a string value for the 'fields' argument. | The `fields` argument was given as a non-string literal. Pass it as a quoted string. |
+| [PROVIDES_INVALID_SYNTAX](https://graphql.github.io/composite-schemas-spec/draft/#sec-Provides-Invalid-Syntax) | The @provides directive on field '\{0\}' in schema '\{1\}' contains invalid syntax in the 'fields' argument. | The selection set syntax in `fields` is invalid. Rewrite it as a valid GraphQL selection set. |
+| [PROVIDES_ON_NON_COMPOSITE_FIELD](https://graphql.github.io/composite-schemas-spec/draft/#sec-Provides-on-Non-Composite-Field) | The field '\{0\}' in schema '\{1\}' includes a @provides directive, but does not return a composite type. | `@provides` only applies when a field returns an object, interface, or union, because the directive describes which sub-fields are also delivered. Remove `@provides`, or change the field to return a composite type. |
+| [QUERY_ROOT_TYPE_INACCESSIBLE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Query-Root-Type-Inaccessible) | The root query type in schema '\{0\}' must be accessible. | The query root cannot be marked `@inaccessible`. Remove the directive from the root query type. |
+| [REFERENCE_TO_INACCESSIBLE_TYPE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Reference-To-Inaccessible-Type) | (Message varies by reference site: field argument, input field, or output field.) | A publicly accessible position (a field argument, input field, or output field) references a type that has been hidden from the composed schema. Either expose the referenced type or change the position to use a publicly accessible type. |
+| [REFERENCE_TO_INTERNAL_TYPE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Reference-To-Internal-Type) | The merged field '\{0\}' in type '\{1\}' cannot reference the internal type '\{2\}'. | A public field returns an internal type, which would leak the internal type into the composed schema. Either mark the field as internal as well, or change the return type to a non-internal one. |
+| [REQUIRE_INVALID_FIELDS](https://graphql.github.io/composite-schemas-spec/draft/#sec-Require-Invalid-Fields) | The @require directive on argument '\{0\}' in schema '\{1\}' specifies an invalid field selection against the composed schema. | The field selection map in `@require(field: ...)` references fields that the parent type does not expose. Update it to reference fields that exist on the parent. See [Entities and Lookups](./entities-and-lookups.md). |
+| [REQUIRE_INVALID_FIELD_TYPE](https://graphql.github.io/composite-schemas-spec/draft/#sec-Require-Invalid-Field-Type) | The @require directive on argument '\{0\}' in schema '\{1\}' must specify a string value for the 'field' argument. | The `field` argument must be a string literal. Pass it as a quoted string. |
+| [REQUIRE_INVALID_SYNTAX](https://graphql.github.io/composite-schemas-spec/draft/#sec-Require-Invalid-Syntax) | The @require directive on argument '\{0\}' in schema '\{1\}' contains invalid syntax in the 'field' argument. | The `field` value is not a valid field selection map. Rewrite it as a syntactically valid field selection map. |
+| [ROOT_MUTATION_USED](https://graphql.github.io/composite-schemas-spec/draft/#sec-Root-Mutation-Used) | The root mutation type in schema '\{0\}' must be named 'Mutation'. | Fusion requires the root mutation type to use the canonical name `Mutation`. Rename the type in the named source schema. A type named `Mutation` must not exist unless it is the root mutation type. |
+| [ROOT_QUERY_USED](https://graphql.github.io/composite-schemas-spec/draft/#sec-Root-Query-Used) | The root query type in schema '\{0\}' must be named 'Query'. | Fusion requires the root query type to use the canonical name `Query`. Rename the type in the named source schema. A type named `Query` must not exist unless it is the root query type. See [Getting Started](./getting-started.md) for the expected schema layout. |
+| [ROOT_SUBSCRIPTION_USED](https://graphql.github.io/composite-schemas-spec/draft/#sec-Root-Subscription-Used) | The root subscription type in schema '\{0\}' must be named 'Subscription'. | Fusion requires the root subscription type to use the canonical name `Subscription`. Rename the type in the named source schema. A type named `Subscription` must not exist unless it is the root subscription type. |
+| [TYPE_KIND_MISMATCH](https://graphql.github.io/composite-schemas-spec/draft/#sec-Type-Kind-Mismatch) | The type '\{0\}' has a different kind in schema '\{1\}' (\{2\}) than it does in schema '\{3\}' (\{4\}). | The same type name was used for different kinds (for example, an object in one source schema and an interface in another). Decide which kind is correct and update the other source schema, or rename one of the types so they no longer collide. |
+| [UNSATISFIABLE_QUERY_PATH](https://graphql.github.io/composite-schemas-spec/draft/#sec-Unsatisfiable-Query-Path) | (Message varies. Includes the unreachable field, the path the validator tried, and the lookups it considered.) | Some reachable field cannot be resolved through the available `@lookup` and `@key` paths. See [Diagnosing UNSATISFIABLE_QUERY_PATH Errors](#diagnosing-unsatisfiable_query_path-errors) for how to read the message and fix the underlying gap. |
## Warnings
diff --git a/website/content/docs/fusion/data-requirements-and-mapping.md b/website/content/docs/fusion/data-requirements-and-mapping.md
index 6b075d570fa..27dcf52a3dd 100644
--- a/website/content/docs/fusion/data-requirements-and-mapping.md
+++ b/website/content/docs/fusion/data-requirements-and-mapping.md
@@ -218,6 +218,24 @@ type Product {
The gateway traverses `seller.address.countryCode` on the entity and passes the resolved value as the `countryCode` argument.
+## Constant Arguments in Field Selections
+
+Fields referenced in a `@require` or `@is` field selection map may carry constant arguments to parameterize or disambiguate the selected field. This is useful when a field offers multiple representations via an argument, and the resolver always needs one specific form.
+
+**GraphQL schema**
+
+```graphql
+# Shipping subgraph
+type Product {
+ shippingCost(size: Int! @require(field: "dimension(unit: METRIC)")): Float
+ dimension(unit: Unit!): Int
+}
+```
+
+Here the `@require` path selects `dimension` with the constant argument `unit: METRIC`. The gateway evaluates this selection against the Products subgraph and passes the resulting value to `shippingCost`.
+
+Argument values in a field selection map must be constant literals (no variables). They must match the field's declared argument definitions, and all required arguments must be supplied. Violations surface as `IS_INVALID_FIELDS` for `@is` and `REQUIRE_INVALID_FIELDS` for `@require`. Note that `@provides` field selections must not include arguments at all; any argument usage there is reported as `PROVIDES_FIELDS_HAS_ARGUMENTS`.
+
## List Aggregation Paths
When an entity field is a list, you can use bracket notation to select a field from each element. The gateway collects the selected values into a flat list.
diff --git a/website/content/docs/fusion/directives-reference.md b/website/content/docs/fusion/directives-reference.md
index 4cc6923278e..b42138a0782 100644
--- a/website/content/docs/fusion/directives-reference.md
+++ b/website/content/docs/fusion/directives-reference.md
@@ -42,6 +42,8 @@ directive @key(fields: FieldSelectionSet!) repeatable on OBJECT | INTERFACE
Each `@key` directive on a type specifies one distinct unique key for that entity. Apply multiple `@key` directives to define alternative keys that the gateway can use to resolve the entity. Fields referenced in a key are implicitly shareable across subgraphs -- you do not need to add `@shareable` to key fields.
+Key fields may supply constant arguments to select a specific variant of a field (for example, `@key(fields: "id(scope: LOCAL)")`). Argument values must be constant literals (no variables), must match the field's declared argument definitions, and all required arguments must be supplied. Composition reports unknown, incompatible, or missing-required arguments as `KEY_INVALID_ARGUMENTS`.
+
**Example -- single key:**
```graphql
@@ -142,7 +144,7 @@ directive @is(field: FieldSelectionMap!) on ARGUMENT_DEFINITION
| -------- | -------------------- | ----------------------------------------------------------------------------- |
| `field` | `FieldSelectionMap!` | A selection map that describes the mapping from entity fields to the argument |
-When a lookup argument name matches the corresponding field on the return type, you can omit `@is`. Use `@is` when the names differ or when the mapping involves nested fields.
+When a lookup argument name matches the corresponding field on the return type, you can omit `@is`. Use `@is` when the names differ or when the mapping involves nested fields. Fields in the selection map may carry constant arguments (for example, `@is(field: "id(scope: LOCAL)")`); argument values must be constant literals (no variables), must match the field's argument definitions, and all required arguments must be supplied. Argument errors surface as `IS_INVALID_FIELDS`.
**Example -- argument name differs from field name:**
@@ -197,7 +199,7 @@ directive @require(field: FieldSelectionMap!) on ARGUMENT_DEFINITION
| -------- | -------------------- | ----------------------------------------------------------------------- |
| `field` | `FieldSelectionMap!` | A selection map describing which fields from the entity type are needed |
-Use `@require` when a resolver in one subgraph needs data that another subgraph owns. The gateway handles the data fetching automatically. This shifts cross-service data dependencies from hidden runtime failures to validated build-time contracts.
+Use `@require` when a resolver in one subgraph needs data that another subgraph owns. The gateway handles the data fetching automatically. This shifts cross-service data dependencies from hidden runtime failures to validated build-time contracts. Fields in the selection map may carry constant arguments to select a specific variant (for example, `@require(field: "dimension(unit: METRIC)")`); argument values must be constant literals (no variables), must match the field's argument definitions, and all required arguments must be supplied. Argument errors surface as `REQUIRE_INVALID_FIELDS`.
**Example -- scalar requirement:**
@@ -290,7 +292,7 @@ directive @provides(fields: FieldSelectionSet!) on FIELD_DEFINITION
| -------- | -------------------- | -------------------------------------------------------------------------------------------------- |
| `fields` | `FieldSelectionSet!` | A field selection set describing the subfields of the returned type that this subgraph can resolve |
-This is a query-planning optimization. When a client requests provided subfields through this particular field path, the gateway resolves them from the current subgraph instead of making a separate call. Fields referenced in `@provides` must be marked `@external` on the return type.
+This is a query-planning optimization. When a client requests provided subfields through this particular field path, the gateway resolves them from the current subgraph instead of making a separate call. Fields referenced in `@provides` must be marked `@external` on the return type. Fields in a `@provides` selection must not have arguments; composition reports any argument usage as `PROVIDES_FIELDS_HAS_ARGUMENTS`.
**Example:**
diff --git a/website/content/docs/fusion/entities-and-lookups.md b/website/content/docs/fusion/entities-and-lookups.md
index ee17b77ac64..0e7671be44b 100644
--- a/website/content/docs/fusion/entities-and-lookups.md
+++ b/website/content/docs/fusion/entities-and-lookups.md
@@ -352,6 +352,8 @@ The `@key(fields: "id")` directive explicitly declares that `Product` is identif
The `fields` value uses GraphQL field names, not C# member names.
+Key fields may supply constant arguments to select a specific variant of a field. For example, `@key(fields: "id(scope: LOCAL)")` selects the `id` field with the constant argument `scope: LOCAL`. Argument values must be constant literals (no variables), must match the field's declared argument definitions, and all required arguments must be supplied.
+
An entity can have multiple keys. Each `@key` directive on a type represents one key.
**GraphQL schema with scalar composite key**
diff --git a/website/content/docs/hotchocolate/defining-a-schema/directives.md b/website/content/docs/hotchocolate/defining-a-schema/directives.md
index 165612c4155..0b505e2e171 100644
--- a/website/content/docs/hotchocolate/defining-a-schema/directives.md
+++ b/website/content/docs/hotchocolate/defining-a-schema/directives.md
@@ -306,6 +306,186 @@ public class FooType : ObjectType
Since the directive instance that we have added to our type is now a strong .NET type, we don't have to fear changes to the directive structure or name anymore.
+## Directives on Directive Definitions
+
+A directive definition is itself a schema element, so it can carry directives. You can use this to mark a directive definition as deprecated or to attach metadata to it, in the same way you annotate object types, fields, or enum values.
+
+To apply a directive to a directive definition, that directive must declare the `DIRECTIVE_DEFINITION` location.
+
+### Declaring a Directive That Targets Directive Definitions
+
+A directive can only be applied to a directive definition when its own definition includes the `DIRECTIVE_DEFINITION` location.
+
+
+
+
+```csharp
+[DirectiveType(DirectiveLocation.DirectiveDefinition)]
+public class OnDirectiveDefinition
+{
+}
+```
+
+
+
+
+```csharp
+public class OnDirectiveDefinitionType : DirectiveType
+{
+ protected override void Configure(IDirectiveTypeDescriptor descriptor)
+ {
+ descriptor.Name("onDirectiveDefinition");
+ descriptor.Location(DirectiveLocation.DirectiveDefinition);
+ }
+}
+```
+
+
+
+
+This configuration translates into the following SDL.
+
+```sdl
+directive @onDirectiveDefinition on DIRECTIVE_DEFINITION
+```
+
+### Applying a Directive to a Directive Definition
+
+Once a directive declares the `DIRECTIVE_DEFINITION` location, you can apply it to another directive definition.
+
+In schema-first SDL you place the applied directives after the argument definitions (if any) and before the optional `repeatable` keyword and the `on` keyword.
+
+```sdl
+directive @onDirectiveDefinition on DIRECTIVE_DEFINITION
+
+directive @custom @onDirectiveDefinition on OBJECT
+```
+
+In code-first, call `Directive(...)` on the `IDirectiveTypeDescriptor` to apply a directive to the directive definition you are configuring.
+
+```csharp
+public class CustomDirectiveType : DirectiveType
+{
+ protected override void Configure(IDirectiveTypeDescriptor descriptor)
+ {
+ descriptor.Name("custom");
+ descriptor.Location(DirectiveLocation.Object);
+ descriptor.Directive("onDirectiveDefinition");
+ }
+}
+```
+
+The descriptor offers the following overloads to apply a directive to the directive definition: `Directive(string name, params ArgumentNode[] arguments)`, `Directive(T instance)`, and `Directive()`.
+
+> [!NOTE]
+> Applying a custom directive to a directive definition is done through the descriptor (Code) or through schema-first SDL.
+
+### Deprecating a Directive Definition
+
+`@deprecated` is allowed on directive definitions and on their arguments. Use it to signal that a directive (or one of its arguments) should no longer be used.
+
+
+
+
+Annotate the directive class with `[Obsolete(...)]` or `[GraphQLDeprecated(...)]`. Both set the deprecation.
+
+```csharp
+[Obsolete("Use @custom instead.")]
+[DirectiveType(DirectiveLocation.Object)]
+public class OldDirective
+{
+}
+```
+
+```csharp
+[GraphQLDeprecated("Use @custom instead.")]
+[DirectiveType(DirectiveLocation.Object)]
+public class OldDirective
+{
+}
+```
+
+
+
+
+Call `Deprecated(...)` on the descriptor.
+
+```csharp
+public class OldDirectiveType : DirectiveType
+{
+ protected override void Configure(IDirectiveTypeDescriptor descriptor)
+ {
+ descriptor.Name("old");
+ descriptor.Location(DirectiveLocation.Object);
+ descriptor.Deprecated("Use @custom instead.");
+ }
+}
+```
+
+
+
+
+In schema-first SDL, apply `@deprecated` to the directive definition or to one of its arguments.
+
+```sdl
+directive @old @deprecated(reason: "Use @custom.") on OBJECT
+
+directive @custom(
+ legacyArg: Int @deprecated(reason: "Use newArg instead.")
+ newArg: String
+) on OBJECT
+```
+
+### Extending a Directive
+
+In schema-first you can use `extend directive` to add directives, including a deprecation, to an existing directive definition. The added directives merge into the existing definition.
+
+```sdl
+directive @custom on OBJECT
+
+extend directive @custom @onDirectiveDefinition
+
+extend directive @custom @deprecated(reason: "Use something else.")
+```
+
+### Introspection
+
+Introspection exposes this surface, mirroring how deprecated fields, enum values, and arguments behave.
+
+- `__Directive` exposes `isDeprecated: Boolean!` and `deprecationReason: String`.
+- `__Schema.directives(includeDeprecated: Boolean = false)` hides deprecated directives by default. Pass `includeDeprecated: true` to include them.
+- `__DirectiveLocation` includes `DIRECTIVE_DEFINITION`.
+
+```graphql
+{
+ __schema {
+ directives(includeDeprecated: true) {
+ name
+ isDeprecated
+ deprecationReason
+ locations
+ }
+ }
+}
+```
+
+### Troubleshooting
+
+**Problem:** The directive definition `@custom` must not reference itself.
+
+- **Cause:** A directive is applied to its own definition or to one of its own arguments. Self-reference is not allowed.
+- **Solution:** Apply a different directive, or remove the self-application.
+
+**Problem:** The specified directive `@onObject` is not allowed on the current location `DirectiveDefinition`.
+
+- **Cause:** The applied directive's definition does not include the `DIRECTIVE_DEFINITION` location.
+- **Solution:** Add `DIRECTIVE_DEFINITION` to that directive's locations (`on DIRECTIVE_DEFINITION` in SDL, or `descriptor.Location(DirectiveLocation.DirectiveDefinition)` in code-first).
+
+**Problem:** The directive extension `extend directive @unknown` targets an undefined directive.
+
+- **Cause:** `extend directive` references a directive that is not defined.
+- **Solution:** Define the directive before extending it.
+
## Locations
A directive can define one or multiple locations, where it can be applied. Multiple locations are separated by a pipe `|`.
@@ -334,6 +514,8 @@ directive @enum on ENUM
directive @enumValue on ENUM_VALUE
directive @union on UNION
directive @scalar on SCALAR
+directive @directiveDefinition on DIRECTIVE_DEFINITION
+directive @custom @directiveDefinition on OBJECT
schema @schema {
query: Query
}
@@ -362,6 +544,8 @@ union SearchResult @union = Product | User
scalar DateTime @scalar
```
+The `DIRECTIVE_DEFINITION` location lets a directive be applied to other directive definitions, as with `@directiveDefinition` on the `@custom` definition above. See [Directives on directive definitions](#directives-on-directive-definitions) for the details.
+
### Executable Locations
Executable locations specify where a client can place a specific directive, when executing an operation.
diff --git a/website/content/docs/hotchocolate/defining-a-schema/versioning.md b/website/content/docs/hotchocolate/defining-a-schema/versioning.md
index c9ea3637fd2..81e48a49337 100644
--- a/website/content/docs/hotchocolate/defining-a-schema/versioning.md
+++ b/website/content/docs/hotchocolate/defining-a-schema/versioning.md
@@ -73,9 +73,9 @@ public class BookQueriesType : ObjectType
# Opt-In Features
-While `@deprecated` marks fields that are going away, `@requiresOptIn` marks fields that are not yet stable. This is useful for rolling out experimental features, expensive operations, or anything where consumers should make a deliberate choice to use it.
+While `@deprecated` marks schema elements that are going away, `@requiresOptIn` marks schema elements that are not yet stable. This is useful for rolling out experimental features, expensive operations, or anything where consumers should make a deliberate choice to use it.
-Fields marked with `@requiresOptIn` are hidden from introspection by default. Consumers opt in by specifying the feature name.
+Schema elements marked with `@requiresOptIn` are hidden from introspection by default. Consumers opt in by specifying the feature name.
## Enabling Opt-In Features
@@ -87,9 +87,9 @@ builder
.ModifyOptions(o => o.EnableOptInFeatures = true);
```
-## Marking Fields as Opt-In
+## Marking Schema Elements as Opt-In
-Apply `@requiresOptIn` to output fields, input fields, arguments, and enum values. The directive is repeatable, so a single field can require multiple features.
+Apply `@requiresOptIn` to output fields, input fields, arguments, enum values, and directive definitions. The directive is repeatable, so a single element can require multiple features.
@@ -148,7 +148,7 @@ Consumers discover opt-in fields by passing the `includeOptIn` argument:
}
```
-The `includeOptIn` argument is available on `fields`, `args`, `inputFields`, and `enumValues` in introspection queries.
+The `includeOptIn` argument is available on `fields`, `args`, `inputFields`, `enumValues`, and `directives` in introspection queries. A directive definition exposes its own required features via `__Directive.requiresOptIn`, mirroring the `requiresOptIn` field on other introspection types.
To discover all opt-in features in the schema:
diff --git a/website/content/docs/mocha/sagas.md b/website/content/docs/mocha/sagas.md
index 67987b1ad9b..80df5292669 100644
--- a/website/content/docs/mocha/sagas.md
+++ b/website/content/docs/mocha/sagas.md
@@ -619,11 +619,11 @@ The correlation lookup order is:
# Timeouts
-A saga that waits for a message that never arrives will stay in its current state forever. Timeouts ensure every saga eventually completes — either through normal processing or by timing out.
+A saga that waits for a message that never arrives will stay in its current state forever. Timeouts ensure every saga eventually completes - either through normal processing or by timing out.
Mocha provides a saga-level `Timeout()` API that sets a single deadline for the entire saga instance. The timeout is scheduled when the saga is created and automatically cancelled when the saga reaches any final state.
-> **Prerequisites:** Durable, cancellable timeouts require a scheduling store. Configure `UsePostgresScheduling()` before using `Timeout()` — see [Scheduling: Set up store-based scheduling](./scheduling.md#set-up-store-based-scheduling-for-rabbitmq) for setup instructions. Native transport scheduling (InMemory, PostgreSQL) also works but does not support automatic cancellation.
+> **Prerequisites:** Durable, cancellable timeouts require a scheduling store. Configure `UsePostgresScheduling()` before using `Timeout()` - see [Scheduling: Set up store-based scheduling](./scheduling.md#set-up-store-based-scheduling-for-rabbitmq) for setup instructions. Native transport scheduling (InMemory, PostgreSQL) also works but does not support automatic cancellation.
## Configure a saga-level timeout
@@ -632,7 +632,7 @@ Call `Timeout()` on the saga descriptor to set a deadline that applies to the en
```csharp
protected override void Configure(ISagaDescriptor descriptor)
{
- // 30-minute timeout — saga will time out if it doesn't reach a final state
+ // 30-minute timeout - saga will time out if it doesn't reach a final state
descriptor.Timeout(TimeSpan.FromMinutes(30))
.Respond(state => new OrderTimedOutResponse(state.Id));
@@ -660,9 +660,9 @@ protected override void Configure(ISagaDescriptor descriptor)
2. Returns an `ISagaFinalStateDescriptor` so you can chain `.Respond()` to send a response when the saga times out.
3. Tells the saga framework to schedule a timeout event when a new saga instance is created.
-The timeout clock starts when the saga is created — that is, when the first event arrives and a new instance is provisioned. If the saga reaches any final state before the deadline, the pending timeout is automatically cancelled. If the timeout fires, a `SagaTimedOutEvent` is delivered to the saga instance.
+The timeout clock starts when the saga is created - that is, when the first event arrives and a new instance is provisioned. If the saga reaches any final state before the deadline, the pending timeout is automatically cancelled. If the timeout fires, a `SagaTimedOutEvent` is delivered to the saga instance.
-Use `OnTimeout()` on a state descriptor to define what happens when the timeout arrives. Handle it the same way you handle any other event — run `.Then()` actions, dispatch commands, or transition to a different state.
+Use `OnTimeout()` on a state descriptor to define what happens when the timeout arrives. Handle it the same way you handle any other event - run `.Then()` actions, dispatch commands, or transition to a different state.
## Key behaviors
@@ -675,7 +675,7 @@ Use `OnTimeout()` on a state descriptor to define what happens when the timeout
| Missing handler | If no `OnTimeout()` handler is configured for the current state, the saga throws an execution error. See [troubleshooting](#timeout-troubleshooting) below. |
| Recommended pattern | `DuringAny().OnTimeout()` handles the timeout regardless of which state the saga is in. |
| Response on timeout | Chain `.Respond()` on the timed-out final state to send a response back to the original requester. |
-| Scheduling store | Requires a scheduling store for durable timeouts. Configure `UsePostgresScheduling()` — see [Scheduling](./scheduling.md#set-up-store-based-scheduling-for-rabbitmq) for setup. Native transport scheduling (InMemory, PostgreSQL) also works but does not support cancellation. |
+| Scheduling store | Requires a scheduling store for durable timeouts. Configure `UsePostgresScheduling()` - see [Scheduling](./scheduling.md#set-up-store-based-scheduling-for-rabbitmq) for setup. Native transport scheduling (InMemory, PostgreSQL) also works but does not support cancellation. |
## Timeout troubleshooting
@@ -697,9 +697,9 @@ descriptor.DuringAny()
| Method | Available on | Parameters | Description |
| ----------- | ------------------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `Initially` | `ISagaDescriptor` | — | Returns the initial state descriptor for defining transitions that create new saga instances. |
+| `Initially` | `ISagaDescriptor` | - | Returns the initial state descriptor for defining transitions that create new saga instances. |
| `During` | `ISagaDescriptor` | `string stateName` | Returns a state descriptor for defining transitions in the named state. |
-| `DuringAny` | `ISagaDescriptor` | — | Returns a catch-all state descriptor whose transitions apply to all non-initial, non-final states. |
+| `DuringAny` | `ISagaDescriptor` | - | Returns a catch-all state descriptor whose transitions apply to all non-initial, non-final states. |
| `Finally` | `ISagaDescriptor` | `string stateName` | Declares a final state. When the saga enters this state, persisted state is deleted and an optional response is sent. |
| `Timeout` | `ISagaDescriptor` | `TimeSpan timeout` | Creates a timed-out final state and schedules automatic timeout on saga creation. Returns `ISagaFinalStateDescriptor` for chaining `.Respond()`. |
@@ -707,11 +707,11 @@ descriptor.DuringAny()
| Method | Available on | Parameters | Description |
| -------------- | ------------------------------ | ---------- | ------------------------------------------------------------------------------------------- |
-| `OnEvent` | `ISagaStateDescriptor` | — | Registers a transition triggered by a published event. |
-| `OnRequest` | `ISagaStateDescriptor` | — | Registers a transition triggered by a request message (captures reply address). |
-| `OnReply` | `ISagaStateDescriptor` | — | Registers a transition triggered by a reply to a previously sent command. |
-| `OnFault` | `ISagaStateDescriptor` | — | Registers a transition triggered by a `NotAcknowledgedEvent`. |
-| `OnTimeout` | `ISagaStateDescriptor` | — | Registers a transition for `SagaTimedOutEvent`. Sugar for `OnRequest()`. |
+| `OnEvent` | `ISagaStateDescriptor` | - | Registers a transition triggered by a published event. |
+| `OnRequest` | `ISagaStateDescriptor` | - | Registers a transition triggered by a request message (captures reply address). |
+| `OnReply` | `ISagaStateDescriptor` | - | Registers a transition triggered by a reply to a previously sent command. |
+| `OnFault` | `ISagaStateDescriptor` | - | Registers a transition triggered by a `NotAcknowledgedEvent`. |
+| `OnTimeout` | `ISagaStateDescriptor` | - | Registers a transition for `SagaTimedOutEvent`. Sugar for `OnRequest()`. |
## Transition actions
@@ -733,8 +733,8 @@ descriptor.DuringAny()
| Method | Available on | Parameters | Description |
| --------------- | ------------------------------ | ---------- | ------------------------------------------------------------------------------------------ |
-| `OnEntry` | `ISagaStateDescriptor` | — | Returns a lifecycle descriptor for actions that run every time the saga enters the state. |
-| `WhenCompleted` | `ISagaDescriptor` | — | Returns a lifecycle descriptor for actions that run when the saga reaches any final state. |
+| `OnEntry` | `ISagaStateDescriptor` | - | Returns a lifecycle descriptor for actions that run every time the saga enters the state. |
+| `WhenCompleted` | `ISagaDescriptor` | - | Returns a lifecycle descriptor for actions that run when the saga reaches any final state. |
# Troubleshooting