Common Issues
This guide covers frequently encountered issues when working with WPGraphQL and their solutions.
Authentication Issues
WPGraphQL itself doesn’t include built-in authentication features. Authentication is handled through extension plugins. For a complete guide to authentication concepts, see the Authentication and Authorization Guide.
Available Authentication Solutions
-
Cookie-based Authentication
- Built into WordPress
- Best for admin-context applications
- Used by WPGraphiQL IDE and other WordPress dashboard integrations
- Requires proper nonce handling
- Limited to same-origin requests
-
- Most comprehensive authentication solution
- Supports multiple authentication methods:
- Traditional WordPress credentials
- OAuth2/OpenID Connect
- JWT tokens
- Application Passwords
- Custom providers
-
- Lightweight JWT-based authentication
- Good for simple authentication needs
- Works well for cross-origin requests
-
WordPress Application Passwords
- Built into WordPress core (5.6+)
- Limited WPGraphQL support currently
- Best for server-to-server authentication
Common Authentication Errors
”Authentication failed” Errors
This typically occurs when:
- No authentication method is configured
- The authentication headers are missing or malformed
- The credentials are invalid
Solution: First, ensure you have an authentication plugin installed and configured. Then verify your authentication headers:
// Example using Application Passwords
$headers = [
'Authorization' => 'Basic ' . base64_encode( 'username:application_password' )
];
// Example using JWT Authentication
$headers = [
'Authorization' => 'Bearer your.jwt.token'
];
Cookie Authentication Issues
For admin-context requests (like WPGraphiQL):
- Verify you’re logged into WordPress
- Check if your session is valid
- Ensure nonce is being sent correctly
// Example of including nonce in requests
const response = await fetch('/graphql', {
method: 'POST',
credentials: 'same-origin',
headers: {
'X-WP-Nonce': wpApiSettings.nonce
}
});
OAuth/Social Login Issues
When using WPGraphQL Headless Login with OAuth providers:
-
Configuration Issues
- Verify OAuth provider credentials
- Check redirect URI configuration
- Ensure SSL is properly configured
-
Integration Issues
- Validate frontend OAuth flow
- Check provider response handling
- Verify user creation/linking settings
For detailed setup instructions and best practices for each authentication method, refer to:
Schema and Type Registration
Common issues related to GraphQL schema and type registration in WPGraphQL.
Custom Post Types Not Showing in Schema
If your custom post type isn’t appearing in the GraphQL schema:
-
Check Show in GraphQL Setting
register_post_type('book', [ 'show_in_graphql' => true, // Must be true 'graphql_single_name' => 'book', // Required 'graphql_plural_name' => 'books', // Highly Recommended // ... other settings ]);
-
Verify Registration Timing
// Post Types must register on `init` hook or earlier add_action('init', function() { register_post_type('book', [ /* ... */ ]); });
-
Common Mistakes
- Not setting the post type
show_in_graphql
totrue
- Missing required `graphql_single_name/graphql_plural_name
- Registering too late in the WordPress lifecycle
- Typos in registration arguments
- Duplicate post type names
- Duplicate
graphql_single_name
/graphql_plural_name
(i.e. 2 post types with the same values)
- Not setting the post type
Missing Fields in Schema
If expected fields are not appearing in your schema:
-
Check Field Registration
register_graphql_field('Post', 'myCustomField', [ 'type' => 'String', 'description' => 'My custom field description', 'resolve' => function($post) { // note the $post is a WPGraphQL Post Model not a WordPress WP_Post object // so you need to use the $post->databaseId property in resolvers instead of the $post->ID property return get_post_meta($post->databaseId, 'my_custom_field', true); } ]);
-
Common Issues
- Field registered too late (use
graphql_register_types
hook instead of hooks likeinit
) - Invalid type specified
- Missing resolve function
- Incorrect field permissions
- Field registered too late (use
Type Registration Errors
Common type registration problems and solutions:
-
Invalid Type Names
// ❌ Invalid: lowercase or special characters, or otherwise non-existing Type in the GraphQL Schema register_graphql_object_type('my-type', [ /* ... */ ]); // ✅ Correct: PascalCase naming register_graphql_object_type('MyType', [ /* ... */ ]);
-
Duplicate Type Registration
// Prevent duplicate registration if (!register_graphql_object_type('MyType')) { register_graphql_object_type('MyType', [ 'fields' => [ 'myField' => ['type' => 'String'] ] ]); }
-
Missing Required Fields
register_graphql_object_type('MyType', [ 'description' => 'Required description field', 'fields' => [ // At least one field is required 'id' => ['type' => 'ID'] ] ]);
Field Resolution Failures
When fields aren’t resolving as expected:
-
Debug Resolution Issues
register_graphql_field('Post', 'debugField', [ 'type' => 'String', 'resolve' => function($post) { // note the $post is a WPGraphQL Post Model not a WordPress WP_Post object // so you need to use the $post->databaseId property in resolvers instead of the $post->ID property // use graphql_debug() to log debug information in the "extensions" portion of the query response - requires GRAPHQL_DEBUG to be enabled graphql_debug('Resolving field for post: ' . $post->databaseId); $value = get_post_meta( $post->databaseId, 'my_field', true ); graphql_debug('Retrieved value: ' . [ '$value' => $value, ]); return $value; } ]);
-
Common Resolution Problems
Incorrect Data Source Access
// ❌ Incorrect: Using WP_Post properties directly register_graphql_field( 'Post', 'myField', [ 'type' => 'String', 'resolve' => function( $post ) { return $post->post_title; // Wrong! $post is not a WP_Post object } ]); // ✅ Correct: Using WPGraphQL Post Model properties register_graphql_field( 'Post', 'myField', [ 'type' => 'String', 'resolve' => function( $post ) { return $post->title; // Correct! Using the Model property } ]);
Missing Null Checks
// ❌ Incorrect: No null checks register_graphql_field( 'Post', 'myMetaField', [ 'type' => 'String', 'resolve' => function( $post ) { $meta = get_post_meta( $post->databaseId, 'my_meta', true ); return $meta; // Could return null/false and cause type coercion errors } ]); // ✅ Correct: With null checks register_graphql_field( 'Post', 'myMetaField', [ 'type' => 'String', 'resolve' => function( $post ) { $meta = get_post_meta( $post->databaseId, 'my_meta', true ); return ! empty( $meta ) ? (string) $meta : null; } ]);
Permission/Capability Issues
// ❌ Incorrect: No capability check register_graphql_field( 'Post', 'secretField', [ 'type' => 'String', 'resolve' => function( $post ) { return get_post_meta( $post->databaseId, 'secret_data', true ); } ]); // ✅ Correct: With capability check register_graphql_field('Post', 'secretField', [ 'type' => 'String', 'resolve' => function($post) { // Check user capabilities before resolving sensitive data if ( ! current_user_can( 'edit_post', $post->databaseId ) ) { throw new \GraphQL\Error\UserError( 'You do not have permission to access this field' ); } return get_post_meta( $post->databaseId, 'secret_data', true ); } ]);
Type Mismatches
// ❌ Incorrect: Type mismatch register_graphql_field( 'Post', 'viewCount', [ 'type' => 'Int', 'resolve' => function( $post ) { return get_post_meta( $post->databaseId, 'view_count', true ); // Returns string from meta } ]); // ✅ Correct: Proper type coercion register_graphql_field( 'Post', 'viewCount', [ 'type' => 'Int', 'resolve' => function( $post ) { $count = get_post_meta( $post->databaseId, 'view_count', true ); return ! empty( $count ) ? absint( $count ) : null; } ]);
Common Debugging Tips
- Enable GRAPHQL_DEBUG in wp-config.php:
define( 'GRAPHQL_DEBUG', true );
- Use graphql_debug() in resolvers:
graphql_debug([ 'message' => 'Debugging resolver', 'data' => $some_data ]);
- Check the “extensions” field in responses for debug info
- Use try/catch blocks to handle errors gracefully:
try { // Your resolver logic } catch (\Exception $e) { graphql_debug([ 'message' => 'Error in resolver', 'error' => $e->getMessage() ]); return null; }
- Enable GRAPHQL_DEBUG in wp-config.php:
For more information about debugging and error handling, see:
For more detailed information about registering types and fields, see:
Query Performance
Common performance issues and their solutions when working with WPGraphQL.
N+1 Query Problems
The N+1 query problem occurs when fetching related data results in multiple separate database queries. WPGraphQL implements several optimizations out of the box to prevent N+1 query problems:
- Post Meta: WordPress automatically batches post meta queries
- Term Relationships: WPGraphQL optimizes term relationship queries
- Author Data: Author data is efficiently loaded for posts
- Comments: Comment queries are optimized when requesting comment counts or comment data
Potential N+1 Scenarios
N+1 issues are most likely to occur when:
-
Working with Custom Database Tables
# This could trigger separate queries if not properly optimized { orders { # WooCommerce example nodes { id # Each of these might query a custom table total lineItems { nodes { productId quantity } } } } }
-
Custom External API Calls
{ posts { nodes { id title # Each of these could trigger separate API calls externalServiceData thirdPartyIntegrationField } } }
Solutions for Custom Data Sources
When working with custom database tables or external APIs, consider:
-
Implement DataLoader Pattern
- Use DataLoader for custom database tables
- Batch external API requests
- Cache frequently accessed data
-
Use Connection Resolvers
- Implement proper connection resolvers for custom relationships
- Utilize WPGraphQL’s built-in connection resolver patterns
For examples of implementing these patterns with custom data sources, see:
Connection Pagination Issues
Common Problems
-
Memory Limits with Large Datasets
# ❌ Problematic: Fetching too many nodes at once { posts(first: 1000) { nodes { # ...fields } } } # ✅ Better: Use pagination with reasonable limits { posts(first: 10) { pageInfo { hasNextPage endCursor } nodes { # ...fields } } }
-
Cursor-based Navigation
# Example of proper cursor-based pagination { posts(first: 10, after: "cursor_string") { pageInfo { hasNextPage endCursor } nodes { id title } } }
Query Optimization Tips
- Request Only Needed Fields
# ❌ Inefficient: Requesting unnecessary fields { posts { nodes { id title content # Don't request if not needed excerpt # Don't request if not needed author { # Triggers additional queries posts { nodes { title } } } } } } # ✅ Efficient: Request only required fields { posts { nodes { id title } } }
Memory Management
-
Configure PHP Memory Limits
// In wp-config.php define( 'WP_MEMORY_LIMIT', '256M' );
-
Implement Query Batching
// Example of batching multiple queries // Note: Query batching only works with POST requests, not GET requests $batch_queries = [ [ 'query' => 'query { posts { nodes { id title } } }' ], [ 'query' => 'query { users { nodes { id name } } }' ] ]; // Send as a single POST request $response = graphql( $batch_queries );
Note: Query batching is only supported when using POST requests. GET requests cannot be batched.
Performance Monitoring
-
Enable Query Logging
// Log slow queries add_filter( 'graphql_debug_enabled', '__return_true' ); // Track query execution time add_action( 'graphql_execute', function( $response, $query ) { graphql_debug([ 'query' => $query, 'execution_time' => timer_stop() ]); }, 10, 2 );
-
Use Query Tracing
// Enable Apollo Tracing add_filter( 'graphql_tracing_enabled', '__return_true' );
For more information about performance optimization, see:
Common Error Messages
”Internal server error”
Common causes and solutions:
-
PHP Memory Limits
// In wp-config.php define( 'WP_MEMORY_LIMIT', '256M' ); define( 'WP_MAX_MEMORY_LIMIT', '512M' );
-
PHP Timeout
// In php.ini or wp-config.php set_time_limit(300); // 5 minutes
-
Server Logs
- Check PHP error logs
- Enable WP_DEBUG for more information
define( 'WP_DEBUG', true ); define( 'WP_DEBUG_LOG', true );
”Sorry, you are not allowed to do that”
This error indicates a permissions issue:
-
Authentication Problems
- Verify user is authenticated
- Check user capabilities
- Ensure authentication headers are correct
- Verify the authentication plugin is properly configured
-
Missing Capabilities
// Check specific capabilities if ( ! current_user_can( 'edit_posts' ) ) { // User doesn't have required capabilities }
-
Common Solutions
- Review the Authentication and Authorization Guide
- Check if user role has necessary permissions
- Verify operation requires authentication
”Field fieldName
is not defined”
This error occurs when requesting non-existent fields:
-
Schema Verification
# Use introspection to check available fields { __type(name: "Post") { fields { name type { name } } } }
Or browse the Schema using the WPGraphQL IDE.
-
Common Causes
- Typos in field names (GraphQL is case-sensitive)
- Fields not registered or registered too late
- Fields registered in the wrong context (e.g., not in the correct post type or taxonomy)
- Fields registered in the wrong hook (e.g., not in the correct hook like
graphql_register_types
) - Fields registered with an already used field name
- Plugin/theme conflicts removing fields
- Custom Post Type or Taxonomy not showing in GraphQL
-
Debug Steps
// Debug field registration add_action( 'graphql_register_types', function() { graphql_debug( 'Registering fields...' ); // Your field registration code }, 9 ); // Check if fields are registered before core
”Cannot return null for non-nullable field”
This error occurs when a non-nullable field resolver returns null:
-
Check Field Definition
// ❌ Problematic: Non-nullable field that might return null register_graphql_field( 'Post', 'myField', [ 'type' => [ 'non_null' => 'String' ], // Non-nullable 'resolve' => function( $post ) { return get_post_meta( $post->databaseId, 'maybe_empty', true ); } ]); // ✅ Better: Make field nullable if data might not exist register_graphql_field( 'Post', 'myField', [ 'type' => 'String', // Nullable 'resolve' => function( $post ) { return get_post_meta( $post->databaseId, 'maybe_empty', true ); } ]);
-
Common Causes
- Meta fields that might not exist
- Incorrect type definitions
- Missing data in resolvers
- Database queries returning no results
For more detailed debugging information, see:
Plugin Conflicts
Common Plugin Issues
-
WPML (WordPress Multilingual)
Common Problems:
- Missing translations in GraphQL responses
- Language switcher not working with GraphQL queries
- Incorrect language context in resolvers
Solutions:
- Use the WPGraphQL WPML extension
- Ensure proper language parameter passing in queries
- Consider implementing custom resolvers for specific translation needs
- Browse past issues and see if there are any solutions for your specific problem.
- Contact the WPML plugin author for support.
-
Post/Term Ordering Plugins
Common Problems:
- Custom order not reflected in GraphQL queries
- Ordering conflicts with WPGraphQL pagination
- Performance issues with large datasets
Solutions:
- Use WPGraphQL’s built-in ordering capabilities where possible
- Implement custom order field resolvers if needed
- Consider using
menu_order
for basic ordering needs - Browse past issues and see if there are any solutions for your specific problem.
- Contact the ordering plugin author for support.
-
Caching Plugins
- WP Super Cache
- W3 Total Cache
- WP Rocket
Common Problems:
- GraphQL responses being incorrectly cached
- Not respecting GraphQL variables in cache keys
Solution: It might be necessary to exclude the GraphQL endpoint from caching for some caching plugins and use something specific like WPGraphQL Smart Cache on a supported host.
-
SEO Plugins For proper SEO data integration, use recommended extensions:
Troubleshooting Steps
-
Identify Conflicts
- Disable plugins one by one to isolate issues
- Use Query Monitor to track unexpected behavior
- Check error logs for plugin-specific errors
-
Common Solutions
- Update plugins to latest versions
- Check for WPGraphQL compatibility
- Look for officially recommended WPGraphQL extensions
- Contact plugin authors about GraphQL support
For more information about plugin compatibility and integration:
Development Environment Issues
Local Development Setup
-
Apache/Nginx Configuration
Common Problems:
- Permalink issues
- ModRewrite not enabled
- CORS issues in headless setups
Solutions:
# Example Apache configuration <IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteRule ^graphql - [L] # ... other rules </IfModule>
-
PHP Configuration
Common Issues:
- Insufficient memory limits
- Short execution time
- Missing required PHP extensions
Solutions:
# php.ini or wp-config.php settings memory_limit = 256M max_execution_time = 300 upload_max_filesize = 64M post_max_size = 64M
Docker Environment
-
Container Communication
Common Issues:
- Cross-container networking
- Volume mounting permissions
- PHP extensions missing in container
Solutions:
# Example docker-compose.yml adjustments services: wordpress: image: wordpress:php8.0 volumes: - ./wp-content:/var/www/html/wp-content environment: WORDPRESS_DEBUG: 1 PHP_INI_MEMORY_LIMIT: 256M
-
Development Tools Integration
Recommendations:
- Use xdebug for PHP debugging
- Configure Query Monitor to track GraphQL queries
- Enable WordPress and GraphQL debugging
// wp-config.php for local Docker environment define( 'WP_DEBUG', true ); define( 'WP_DEBUG_LOG', true ); define( 'GRAPHQL_DEBUG', true );
Query Monitor will automatically track GraphQL queries when WPGraphQL is installed and WPGraphQL will show the query logs when GraphQL Query Logging is enabled.
Testing Environment
When developing with WPGraphQL, it’s important to have a proper testing environment:
-
Local Development Environment
- Use a development-specific wp-config.php
- Enable debugging
- Configure error logging
// wp-config.php define( 'WP_DEBUG', true ); define( 'WP_DEBUG_LOG', true ); define( 'GRAPHQL_DEBUG', true );
-
Testing Best Practices
- Test queries in GraphiQL IDE before implementation
- Verify schema changes with introspection queries
- Test with different user roles and permissions (including public vs logged in users)
- Validate mutations with sample data
For more detailed information about testing WPGraphQL, see:
Debugging Strategies
WPGraphQL provides several debugging tools and strategies. For comprehensive debugging information, see the Debugging Guide.
Common debugging approaches:
-
Enable Debug Mode
- Enable from WPGraphQL Settings page
- Or add to wp-config.php:
define( 'GRAPHQL_DEBUG', true );
-
Use Query Monitor
- Tracks GraphQL queries
- Shows database queries
- Monitors performance
- Outputs to the GraphQL response when GraphQL Query Logging is enabled
-
Debug Response Data
- Use
graphql_debug()
to add debug info to response - Enable Query Logging to see SQL queries in response
- Enable Tracing to see resolver timing in response
- Check the “extensions” portion of responses for debug data
Note: Debug information is only available in the response and is not persisted to logs.
- Use
-
Common Debug Steps
- Test queries in GraphiQL IDE first
- Check server logs for PHP errors
- Verify proper hook timing
- Test with minimal active plugins
For detailed information about each debugging method, examples, and troubleshooting tips, see the Debugging Guide.
Common Configuration Mistakes
WordPress Configuration
-
Permalink Structure
- Recommended to be set to “Post name” or another pretty permalink structure
- Default permalink structure can technically work with WPGraphQL, but is not recommended.
-
PHP Version
- WPGraphQL requires PHP 7.4 or higher
- Recommended to use latest stable PHP version (8.x)
- Some features may require newer PHP versions
Server Configuration
-
Memory Limits
// Recommended minimum settings define( 'WP_MEMORY_LIMIT', '256M' ); define( 'WP_MAX_MEMORY_LIMIT', '512M' );
-
Execution Time
// Adjust based on your needs set_time_limit(300); // 5 minutes ini_set('max_execution_time', 300);
-
POST Request Size
# php.ini settings upload_max_filesize = 64M post_max_size = 64M
Common Misconfigurations
-
CORS Settings
- WPGraphQL allows all origins by default (
Access-Control-Allow-Origin: *
) - Only modify if you need to restrict to specific domains
// Example: Restrict to specific domain add_filter( 'graphql_response_headers_to_send', function( $headers ) { // Only modify if you need to restrict access $headers['Access-Control-Allow-Origin'] = 'https://your-frontend-domain.com'; return $headers; });
Note: The default CORS configuration works for most setups. Only modify if you have specific security requirements.
- WPGraphQL allows all origins by default (
-
SSL Configuration
- Mixed content issues with HTTPS
- Certificate validation problems
- Incorrect site URL configuration
// Force HTTPS for GraphQL endpoint if ( ! is_ssl() && 'graphql' === $GLOBALS['wp']->request ) { wp_redirect( 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] ); exit(); }
-
File Permissions
- Upload directory permissions
- Plugin directory access
- WordPress core file permissions
# Recommended permissions chmod 755 wp-content/plugins chmod 755 wp-content/themes chmod 755 wp-content/uploads
For more detailed configuration information, see: