
Diagnosing 404s for encoded caret paths
A request for a path containing a caret (^) may return a 404 even when you expect the route or file to exist. A 404 means the responding server or application did not find a matching resource. It does not, by itself, show whether the problem is URL encoding, request parsing, route matching, or a missing resource.
This guide uses the reported server-core issue as a starting point for diagnosis. The supplied issue link identifies the topic, but the record does not include its technical details or a confirmed fix. The example below is a general diagnostic pattern, not a reproduction of that issue or a claim that it has been tested.
What to check first
Compare the path at each stage: the URL your client sends, the request received by the server, and the path used for routing or file lookup. A caret may be represented literally or percent-encoded as %5E. These forms can be handled differently by clients, proxies, frameworks, and application code.
For example, these requests express a caret in different ways:
GET /assets/revision^2.js
GET /assets/revision%5E2.js
Do not assume that every component decodes or normalises the path in the same way. Also avoid decoding it repeatedly: a second decoding pass can change the meaning of a path that already contains encoded characters.
Minimal diagnostic example
Suppose your application is expected to serve a resource at this path:
/assets/revision^2.js
Try the following controlled comparison in an environment where you are authorised to make requests. Use the same host, method, headers, and deployment for both requests:
curl -i 'https://example.test/assets/revision%5E2.js'
curl -i 'https://example.test/assets/revision^2.js'
Replace example.test with your own host. Treat these as example commands, not as evidence of a particular server’s behaviour. If the response differs, record the status, response headers, and any request identifier. Do not include credentials or sensitive query values when sharing logs.
If you are testing a route rather than a static file, make the comparison against the exact route that should match. A route may have its own rules for path parameters, wildcards, or encoded characters.
Likely causes
1. The resource or route is not present
A 404 may be correct if the file was not included in the build, the route is registered under a different prefix, or the request is reaching the wrong deployment. Confirm that the expected resource exists in the output and that the request uses the intended host and base path.
2. Different URL representations reach different code paths
A client, proxy, server, or framework may preserve, decode, or normalise path characters before routing. If one layer sees %5E and another sees ^, route matching or file lookup may not behave as expected. Compare the incoming request with the path your application actually uses, using the logging facilities available in your stack.
3. A proxy or server rule changes the request
Reverse proxies, gateways, rewrite rules, and static-file servers can affect which path is forwarded or matched. If the application works when accessed directly but fails through a proxy, compare the request at both boundaries. Change one layer at a time so you can identify where the difference appears.
4. Application code decodes or normalises the path incorrectly
Look for custom decoding, path cleanup, or string replacement before route matching or file access. Repeated decoding is a particular risk: the application should not casually transform a path more than once. Use the framework’s documented path-handling APIs rather than adding a global workaround without understanding its effects.
5. The behaviour depends on the installed version or configuration
Routing and request-parsing behaviour can depend on the framework, server, and proxy versions and settings. The supplied record does not establish which version is affected or provide an official version-specific fix. Check the documentation and release notes for the exact versions in your project before changing configuration or upgrading.
Safe diagnostic path
- Write down the expected path. Record the route or resource path as the application expects it, including its prefix and filename.
- Compare encoded and literal forms. Send otherwise identical requests and note whether their status or response changes. Keep the test in a safe environment if the path could trigger sensitive application behaviour.
- Check the deployed resource or route. Confirm that the file exists in the deployed output or that the intended route is registered. Check the active environment and base path as well.
- Trace the request through each layer. Check available logs at the edge proxy, application server, and router. Compare the path each layer records. Redact secrets and personal data before sharing logs.
- Review custom path handling. Search for decoding, rewriting, or normalisation performed before route matching or file lookup. Remove unnecessary transformations and follow the relevant framework documentation.
- Check versions and settings. Note the versions of the server, framework, and any proxy involved. Consult their current official documentation for behaviour and supported configuration. Avoid applying an undocumented workaround based only on a similar-looking report.
- Make one change at a time. If you find a configuration or code change to try, test it in a controlled environment first. Keep a way to revert it, and check that ordinary routes still work.
Choosing and applying a fix
There is no single safe fix for every encoded-caret 404. First identify the layer where the request stops matching the expected path. Then use that layer’s supported configuration or API.
- If the resource is missing, correct the build, deployment, filename, or requested base path.
- If a route does not match, review its definition and the framework’s documented handling of path characters.
- If a proxy changes the path, adjust the relevant rewrite or forwarding configuration using that proxy’s documentation.
- If custom code decodes the path, remove unnecessary decoding or make the transformation consistent with the framework’s documented approach.
- If the behaviour appears version-specific, check official release notes and documentation for the versions you actually run before upgrading or downgrading.
Do not broadly decode every request path or block all paths containing carets as a quick fix. Either change can affect unrelated routes or resources. Keep the change narrow, review its security implications, and confirm it does not alter normal path handling unexpectedly.
How to verify a fix
Repeat the original request using the same host and relevant request settings. Check that the expected resource or route responds correctly, and compare the server’s recorded path with the path you intended to request.
Also test nearby cases:
- The literal-caret and percent-encoded forms, if your application is intended to support both.
- A normal route or filename without a caret.
- A path that should not exist, to confirm that genuine missing resources still return the expected not-found response.
- The same request through the usual proxy or gateway, not only against a direct local endpoint.
These checks help catch a fix that makes one request work but breaks other routes or changes how missing resources are handled.
Common follow-up questions
Should I always encode the caret as %5E?
Not necessarily. The correct representation depends on the client, route, and components between the client and application. Compare both forms and follow the documentation for the libraries and server involved. Do not treat encoding alone as proof that the route or resource exists.
Is a 404 proof that the application rejected the caret?
No. The response could come from a proxy, server, router, or file lookup. Use logs or other observability available in your environment to identify which component generated the response before changing application code.
References
- Modern.js GitHub issue: encoded caret paths returning 404 in server-core
- Stack Overflow questions (general reference; not official framework documentation)
Dont SPAM