Skip to main content

Troubleshooting

Common issues and solutions when using the GraphQL Code Generator.

Compilation Errors

Generated Code Not Found

Symptoms:

1
error: package com.example.generated does not exist
2
error: cannot find symbol

Causes & Solutions:

  1. Generated code directory not in source sets
1
sourceSets {
2
main {
3
java {
4
srcDir 'build/generated/graphql' // Add this
5
}
6
}
7
}
  1. Code generation didn't run
1
# Run generation manually
2
./gradlew generateGraphQLCode
3
4
# Or regenerate everything
5
./gradlew clean generateGraphQLCode compileJava
  1. IDE not recognizing generated sources

IntelliJ IDEA:

  • Right-click project → "Reload Gradle Project"
  • Or: File → Invalidate Caches → Restart

Eclipse:

  • Right-click project → Gradle → Refresh Gradle Project

VS Code:

  • Reload window (Cmd/Ctrl + Shift + P → "Reload Window")

Circular Dependency Error

Symptoms:

1
Circular dependency between the following tasks:
2
:compileJava
3
\--- :generateGraphQL
4
\--- :compileJava (*)

Cause: The code generator class needs to be compiled before it can run, but it depends on code generation completing.

Solution: Put your generator class in a separate source set:

1
sourceSets {
2
codegen {
3
java {
4
srcDir 'src/codegen/java'
5
}
6
}
7
}
8
9
tasks.register('generateGraphQLCode', JavaExec) {
10
// Use codegen classpath, not main
11
classpath = sourceSets.codegen.runtimeClasspath
12
mainClass = 'com.example.codegen.MyCodeGenerator'
13
}

Or use a separate buildSrc module for your generator.


Package Name Mismatch

Symptoms:

1
error: class MySchemaContext is public, should be declared in a file named MySchemaContext.java

Cause: The generated package doesn't match the directory structure.

Solution: Ensure your packageName in the generator matches the output directory structure:

1
new GraphQLCodeGenerator.Builder()
2
.generatedSourcesPackageName("com.example.generated") // Must match directory
3
.generatedSourcesOutputDir("build/generated/graphql")
4
.build();

The generator creates: build/generated/graphql/com/example/generated/MySchemaContext.java


Runtime Errors

Conversion Boilerplate Everywhere

Symptoms: Every query and mutation method ends with the same hand-written domain-to-model wrapping.

Cause: The schema doesn't map the type to your domain class, so generated signatures use the generated models and you convert at every call site.

Solution: Add a @javaType directive to your schema (or an addTypeMapping builder call). Generated signatures then use your domain class directly, and the schema context declares a single to<Type> converter you implement once:

1
type User @javaType(class: "com.example.domain.User") {
2
id: ID!
3
name: String!
4
}

See Pattern 1: Type Mappings.


NullPointerException Resolving a Field

Symptoms:

1
NullPointerException at MySchemaContextImpl.toUser(MySchemaContextImpl.java:42)

Cause: A query method or converter assumed non-null data.

Solution: Handle null cases—nullable GraphQL fields should resolve to null, not throw:

1
@Override
2
public MyPost post(String id) {
3
DomainPost domain = postService.findById(id);
4
5
// Return null for not found (GraphQL semantics)
6
if (domain == null) {
7
return null;
8
}
9
10
return toPost(domain);
11
}

Schema Errors

Scalar Type Not Found

Symptoms:

1
Unknown type 'UUID' in field 'id'

Cause: Custom scalar not registered with the generator.

Solution: Add scalar mapping:

1
new GraphQLCodeGenerator.Builder()
2
.sdlPath("src/main/resources/schema.graphql")
3
.generatedSourcesPackageName("com.example.generated")
4
.addCustomScalar("UUID", UuidScalar.class) // Add this
5
.build();

The scalar must also be declared in the SDL (scalar UUID).


Directive Not Recognized

Symptoms:

1
Unknown directive '@javaType'

Cause: The @javaType directive must be defined in your schema.

Solution: Add the directive definition:

1
directive @javaType(
2
class: String!
3
) on OBJECT | INTERFACE | UNION

Conflicting Type Names

Symptoms:

1
error: duplicate class: com.example.generated.Query

Cause: Generated type name conflicts with an existing class.

Solution: Use classNamePrefix:

1
new GraphQLCodeGenerator.Builder()
2
.sdlPath("src/main/resources/schema.graphql")
3
.generatedSourcesPackageName("com.example.generated")
4
.classNamePrefix("MyAPI") // Generates MyAPIQuery instead of Query
5
.build();

Gradle Build Issues

Code Generation Runs Every Build

Symptoms: Build always regenerates code even when schema hasn't changed.

Cause: Missing input/output declarations.

Solution:

1
tasks.register('generateGraphQLCode', JavaExec) {
2
// ...existing configuration...
3
4
// Add these for incremental builds
5
inputs.files(fileTree('src/main/resources/graphql'))
6
outputs.dir('build/generated/graphql')
7
}

Out of Memory During Generation

Symptoms:

1
java.lang.OutOfMemoryError: Java heap space

Cause: Very large schema or insufficient heap size.

Solution:

1
tasks.register('generateGraphQLCode', JavaExec) {
2
// ...existing configuration...
3
4
jvmArgs = ['-Xmx2g'] // Increase heap size
5
}

Build Cache Not Working

Symptoms: Code regenerates even with identical inputs.

Cause: Task not properly configured for caching.

Solution:

1
tasks.register('generateGraphQLCode', JavaExec) {
2
// ...existing configuration...
3
4
// Declare all inputs
5
inputs.file('src/main/resources/schema.graphql')
6
inputs.file('src/main/java/com/example/codegen/MyCodeGenerator.java')
7
8
// Declare outputs
9
outputs.dir('build/generated/graphql')
10
.withPropertyName('outputDir')
11
12
// Enable caching
13
outputs.cacheIf { true }
14
}

Implementation Errors

Type Safety Violations

Symptoms:

1
warning: [unchecked] unchecked conversion

Cause: Using raw types or incorrect generic types.

Solution: Use proper generic types:

1
// Wrong
2
List posts() {
3
return domainPosts.stream()
4
.map(this::toPost)
5
.collect(Collectors.toList());
6
}
7
8
// Right
9
List<MyPost> posts() {
10
return domainPosts.stream()
11
.map(this::toPost)
12
.collect(Collectors.toList());
13
}

Sealed Class Violations

Symptoms: A MySealedClassException is thrown, or you're tempted to implement a generated interface (like a union type) directly.

Cause: Generated models are sealed by design—generated interfaces declare a sealed(...) method that only the generated abstract classes implement, so arbitrary anonymous implementations are rejected.

Solution: Don't implement generated interfaces directly. Extend (or create anonymous instances of) the generated abstract classes instead—e.g. return a MyProduct (which implements MySearchResult) rather than implementing MySearchResult yourself.


Union Type Resolution Fails

Symptoms:

1
GraphQLError: Abstract type SearchResult must resolve to an Object type

Cause: A union field returned an object that isn't an instance of any generated member model, so the generated type resolver couldn't identify it.

Solution: Return instances of the generated member classes—resolution is automatic from there:

1
@Override
2
public MySearchResult search(String query) {
3
Object result = searchService.search(query);
4
5
if (result instanceof DomainProduct) {
6
return toProduct((DomainProduct) result); // a MyProduct
7
} else if (result instanceof DomainArticle) {
8
return toArticle((DomainArticle) result); // a MyArticle
9
} else if (result == null) {
10
return null;
11
} else {
12
throw new IllegalStateException(
13
"Unexpected search result type: " + result.getClass().getName());
14
}
15
}

Performance Issues

Slow Query Resolution

Symptoms: GraphQL queries take a long time to execute.

Causes & Solutions:

  1. N+1 Query Problem
1
// Bad: Loads author for each post separately
2
@Override
3
public MyAuthor author() {
4
return toAuthor(userService.findById(post.getAuthorId()));
5
}
6
7
// Good: Batch load all authors upfront
8
@Override
9
public List<MyPost> posts() {
10
List<DomainPost> domainPosts = postService.findAll();
11
12
// Pre-load all authors in single query
13
Set<String> authorIds = domainPosts.stream()
14
.map(DomainPost::getAuthorId)
15
.collect(Collectors.toSet());
16
17
Map<String, DomainUser> authors = userService.findByIds(authorIds)
18
.stream()
19
.collect(Collectors.toMap(DomainUser::getId, u -> u));
20
21
// Return posts with pre-loaded authors
22
return domainPosts.stream()
23
.map(post -> toPost(post, authors.get(post.getAuthorId())))
24
.collect(Collectors.toList());
25
}
  1. Unnecessary Field Resolution

Use lazy loading for expensive fields (see Implementation Patterns).


Getting Help

If you're still experiencing issues:

  1. Check the logs: Enable debug logging for com.psddev.graphql
  2. Verify schema: Use a GraphQL schema validator
  3. Compare with examples: See Advanced Examples
  4. Simplify: Create a minimal reproduction case
  5. Ask for help: Include your schema, generated code, and error messages

Next Steps

Was this page helpful?

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.