Subchapter 2.4
references/troubleshooting.mdMarkdown8 KBView on GitHub
Common errors and solutions when working with Apollo Connectors.
Problem: Trying to concatenate strings with +.
# WRONG
fullName: firstName + " " + lastNameSolution: Use ->joinNotNull with an array.
# CORRECT
fullName: $([firstName, lastName])->joinNotNull(' ')
# With more parts
address: $([street, city, state, zip])->joinNotNull(', ')Problem: Literal values in mappings without the $() wrapper.
# WRONG - Will not compose
body: "{ userId: $args.id }"
greeting: "Hello"
count: 42Solution: Wrap literals in $().
# CORRECT
body: "$({ userId: $args.id })"
greeting: $("Hello")
count: $(42)
isActive: $(true)Problem: Trying to use bracket notation for array access.
# WRONG
firstItem: items[0]
thirdItem: items[2]Solution: Use array methods.
# CORRECT
firstItem: items->first
lastItem: items->last
thirdItem: items->get(2)
firstThree: items->slice(0, 3)Problem: An entity type is missing a @connect directive.
Error: MISSING_ENTITY_CONNECTOR
Entity "User" is missing a connector.Cause: You’ve referenced a type as an entity (via stub or @key) but haven’t defined how to resolve it.
Solution: Add @connect to the entity type.
# Add @connect to make it a resolvable entity
type User @connect(
source: "api"
http: { GET: "/users/{$this.id}" }
selection: "id name email"
) {
id: ID!
name: String
email: String
}Or, if it shouldn’t be an entity, remove the entity stub and inline the data.
Problem: Request body not properly formatted.
Error: INVALID_BODY
Body must use literal syntax.Cause: Object literal in body without $() wrapper.
# WRONG
body: "{ userId: $args.id }"Solution: Use $() for object literals.
# CORRECT
body: "$({ userId: $args.id })"
# For nested objects
body: "$({ user: { id: $args.id, name: $args.name } })"Problem: Using == for equality comparison.
# WRONG
isActive: status == "active"
is200: $status == 200Solution: Use the ->eq method.
# CORRECT
isActive: status->eq("active")
is200: $status->eq(200)For HTTP status checks with simple boolean returns:
# For DELETE operations that should return true on success
selection: "$(true)"Problem: Using ternary operator for conditional values.
# WRONG
result: condition ? valueA : valueBSolution: Use null coalescing operators.
# Use ?? for null/undefined fallback
result: value ?? "default"
# Use ?! for undefined-only fallback (preserves null)
result: value ?! "fallback"
# Use ->match for value mapping
result: status->match(
["active", "Active User"],
["inactive", "Inactive User"],
[@, "Unknown"]
)Problem: Using ->and inside filter or find.
# WRONG - @ changes meaning in nested method
items: $.list->filter(@.active->and(@.price->gt(10)))Cause: The @ variable refers to different values in nested contexts.
Solution: Chain filter calls.
# CORRECT - Chain filters
items: $.list->filter(@.active)->filter(@.price->gt(10))
# For find
item: $.list->filter(@.active)->find(@.price->gt(10))Problem: Entity stubs create a circular dependency.
Error: Circular reference detected between Product and ReviewCause: Product has reviews, Review has product, both as entity stubs.
Solution: Use @inaccessible foreign key pattern.
type Product {
id: ID!
reviews: [Review] @connect(
http: { GET: "/products/{$this.id}/reviews" }
selection: "id rating text productId" # Include FK
)
}
type Review {
id: ID!
rating: Int
text: String
productId: ID! @inaccessible # Hide from clients
product: Product @connect(
http: { GET: "/products/{$this.productId}" }
selection: "id name"
)
}Problem: Accessing header value directly.
# WRONG - Headers are arrays
auth: $request.headers.authorizationSolution: Use ->first to get the first value.
# CORRECT
auth: $request.headers.authorization->first
# For headers with special characters
custom: $request.headers.'x-custom-header'->firstProblem: Using $ when selecting from root.
# WRONG - Unnecessary
selection: """
$ {
id
name
}
"""Solution: Select fields directly.
# CORRECT
selection: """
id
name
"""Use $ only when:
$.results { id }$->first { id }Problem: Schema won’t compose due to version mismatch.
Error: Incompatible federation and connect versionsSolution: Use the correct version combination.
# CORRECT - Always use these versions together
extend schema
@link(url: "https://specs.apollo.dev/federation/v2.12")
@link(url: "https://specs.apollo.dev/connect/v0.3", import: ["@source", "@connect"])Problem: Want to create an entity but there’s no API endpoint for it.
Solution: Don’t make it an entity. Use a regular type.
# If there's no /address/{id} endpoint, don't make it an entity
type Address { # No @connect, no @key
street: String
city: String
country: String
}
# Include it inline in the parent's selection
type User @connect(
http: { GET: "/users/{$this.id}" }
selection: """
id
name
address {
street
city
country
}
"""
) {
id: ID!
name: String
address: Address
}Problem: Test expectations don’t match actual output.
Cause: connectorResponse in tests is the selection mapping result, not the final GraphQL response.
# apiResponseBody from REST API
apiResponseBody: |
{ "user_id": "123", "user_name": "Alice" }
# Selection mapping
selection: """
id: user_id
name: user_name
"""
# connectorResponse is the mapping result
connectorResponse: |
{ "id": "123", "name": "Alice" }Note: No type conversion unless explicitly done with ->parseInt, ->toString, etc.
Problem: Using $batch but API doesn’t support batch requests.
Solution:
# Non-batch (N+1)
type Product @connect(
http: { GET: "/products/{$this.id}" }
selection: "id name"
) {
id: ID!
name: String
}
# Batch (requires API support)
type Product @connect(
http: {
POST: "/products/batch"
body: "ids: $batch.id"
}
selection: "id name"
) {
id: ID!
name: String
}