Troubleshooting
This guide covers common errors you may encounter when building, deploying, and running your Zuplo API gateway, along with steps to diagnose and fix them.
Build errors
Build errors prevent your project from compiling during deployment. The gateway
returns a BUILD_ERROR when this happens.
TypeScript compilation errors
Type mismatches, missing type definitions, or invalid syntax prevent the build from completing. Check the deployment logs for the file name, line number, and error description.
Fix: Run the build locally before deploying to catch these errors early:
Code
You can also add TypeScript to your project and run type checking directly:
Code
This catches type errors before you deploy and integrates with most editors for inline feedback.
Module resolution failures
Imports that do not start with ./ or ../ and have no matching paths
mapping in tsconfig.json fail to resolve.
Code
Fix: Use relative paths for local modules, or configure
compilerOptions.paths in your tsconfig.json. See
TypeScript Configuration for details.
Missing or incompatible packages
Zuplo does not run Node.js and does not run npm install during deployment.
Only npm packages that don't use native code or Node.js-specific APIs (like the
filesystem or child_process) are compatible. Packages must be installed
locally and their bundled output checked into source control.
Fix: Install the package locally, verify it works with zuplo dev, and
ensure the compiled output is committed to your repository. See
Node Modules for details on package
compatibility and limitations.
Invalid route configuration
The routes.oas.json file contains syntax errors or references handlers and
policies that do not exist.
Fix: Validate that all handler.module and handler.export values in your
route configuration match actual modules and exported functions. Check for typos
in policy names referenced in the policies.inbound and policies.outbound
arrays.
Deployment errors
FATAL_PROJECT_ERROR
The gateway returns this error when the project has a critical configuration issue that prevents it from starting.
Fix: Check the deployment logs in the Zuplo Portal for the specific error
message. Common causes include invalid zuplo.runtime.ts configuration or
broken runtime extensions.
MAIN_MOD_ERROR
This error indicates that the main module failed to load at startup.
Fix: Verify that your zuplo.runtime.ts file (if present) exports valid
configuration and that all plugins are properly initialized. Check for runtime
errors in module-level code that runs during startup.
NO_PROJECT_SET
This error typically occurs in local development when trying to run a project that cannot build or is invalid.
Fix: Verify that your project structure is correct and that the project builds successfully. See Local Development Troubleshooting for more details.
Runtime errors
Policy errors
When a policy throws an unhandled error, the gateway returns a 500 response.
Use RuntimeError or ConfigurationError from @zuplo/runtime to return
structured error responses instead.
Code
See Runtime Errors for the full API.
Handler errors
If a request handler throws an unhandled exception, the gateway returns a generic error response. Wrap handler logic in try/catch blocks and return meaningful error responses.
Code
Timeout errors
Requests to upstream services can time out if the backend is slow or unresponsive. The gateway enforces platform-level timeouts on outbound requests.
Fix: Check that your upstream service is healthy and responding within
acceptable timeframes. Add timeout handling in custom handlers using
AbortSignal.timeout():
Code
Debugging with logs
Portal live logs
The Zuplo Portal provides real-time log viewing for deployed environments.
Navigate to your project in the portal and open the logs tab to see live request
logs and any messages logged with context.log.
Using context.log
The context.log object is available in all handlers and policies. It supports
debug, info, warn, and error levels:
Code
You can also attach custom properties to all subsequent log entries for a
request using context.log.setLogProperties:
Code
Log shipping
For production observability, ship logs to an external provider by configuring a
log plugin in your zuplo.runtime.ts file. Supported providers include AWS
CloudWatch, Datadog, Dynatrace, Google Cloud Logging, Loki, New Relic, Splunk,
and Sumo Logic.
See Logging for setup instructions.
Request tracing with zp-rid
Every request processed by Zuplo is assigned a unique request ID. This ID is
returned in the zp-rid response header and is available in code as
context.requestId.
To trace a failed request:
- Copy the
zp-ridvalue from the response headers. - Search your log provider (Datadog, Loki, Splunk, etc.) for that
requestIdvalue. - All log entries for that request share the same
requestId, so you can see the full request lifecycle.
You can also log the request ID explicitly for correlation:
Code
Default log fields include requestId, environment, environmentType,
environmentStage, buildId, and rayId, which you can use to filter and
correlate across requests.
Common gotchas
Environment variables not set
Environment variables are only applied on new deployments. If you change a variable value, you must redeploy the environment for the change to take effect.
Variables return undefined if not set. Always validate required variables
early:
Code
See Configuring Environment Variables for more details.
CORS misconfiguration
Common CORS issues include:
- No CORS headers in response - Verify the route has a
corsPolicyset (notnone) and that the requestOriginmatches one of theallowedOrigins. - Preflight returns 404 - Ensure the CORS policy is not set to
noneand the request method matches a method configured on the route. - Wildcard subdomain not matching - The
*.pattern only matches a single subdomain level.https://*.example.comdoes not matchhttps://v2.api.example.comorhttps://example.com. - Credentials not working - Set
allowCredentialstotruein the CORS policy.
See Configuring CORS for the full configuration reference.
Rate limit surprises
Rate limiting policies apply per-environment. Preview and development environments have their own rate limit counters separate from production.
If requests are unexpectedly rate limited, check:
- The rate limit policy configuration for the correct
requestsAllowedandtimeWindowMinutesvalues. - Whether a per-user or per-IP rate limit is in use and the identifier is resolving correctly.
- Whether multiple rate limit policies are applied to the same route.
See Rate Limiting for configuration details.
GET or HEAD requests with a body
Sending a body with a GET or HEAD request results in a GET_HEAD_BODY_ERROR
response. Some HTTP clients attach a body by default.
Fix: Remove the request body for GET and HEAD requests, or change the
HTTP method to POST or PUT if a body is required.
Getting help
If you cannot resolve an issue using this guide:
- Check the Zuplo Errors reference for detailed error descriptions.
- Reach out to support@zuplo.com or join the Zuplo Discord server.