Skip to content

Troubleshooting

Common problems

Multiple decisions for the same request

If you are seeing multiple decisions for the same request, it is likely that Arcjet is running in multiple places in your application. This can happen if you are using a middleware and also calling the Arcjet SDK in a route handler.

You can fix this by ensuring that Arcjet is only called once per request. You can combine multiple rules into a single client configuration and/or you can exclude routes from your middleware.

Common errors

[unauthenticated] invalid key

✦Aj Encountered problem getting remote decision: [unauthenticated] invalid key

This error means that the Arcjet key you are using is invalid. Each site has a unique key to identify it within Arcjet. You can find your key in the Arcjet dashboard by clicking your site name and then going to the SDK installation tab.

Arcjet keys are always prefixed with ajkey_

You provide the Arcjet SDK with the key when instantiating the client. For example in this case the key is defined in an environment variable called ARCJET_KEY:

import arcjet from "arcjet";
const aj = arcjet({
// Get your site key from https://app.arcjet.com
// and set it as an environment variable rather than hard coding.
// See: https://www.npmjs.com/package/dotenv
key: process.env.ARCJET_KEY,
rules: [
// Protect against common attacks with Arcjet Shield
shield({
mode: "LIVE", // will block requests. Use "DRY_RUN" to log only
}),
],
});

[deadline_exceeded] the operation timed out

✦Aj Encountered problem getting remote decision: [deadline_exceeded] the operation timed out
ConnectError: [deadline_exceeded] the operation timed out

This error means that the Arcjet SDK was unable to connect to the Arcjet API within the short timeout period. This is usually caused by a network issue. The SDK is designed to fail open so that in the event of a network problem or outage, requests will be allowed.

If you are seeing this error frequently, please contact us so we can investigate.

[failed_precondition] request details failed validation

Arcjet expects certain fields to exist on the object used to analyze each request. This is normally handled by the SDK for the framework you are using, but if you are doing something custom then you will need to provide the correct fields:

The required fields are:

  • ip - The client IP address. Internally our SDKs use our @arcjet/ip package to detect the correct IP which you can also use directly.
  • method - The HTTP method of the request.
  • host - The host of the request.
  • path - The path of the request.
  • headers - The headers of the request.

Here are some examples of how to provide these fields:

This example uses a pure Node.js server:

import { createConnectTransport } from "@connectrpc/connect-node";
import arcjet, { createRemoteClient, defaultBaseUrl, shield } from "arcjet";
import * as http from "http";
const aj = arcjet({
// Get your site key from https://app.arcjet.com
// and set it as an environment variable rather than hard coding.
// See: https://www.npmjs.com/package/dotenv
key: process.env.ARCJET_KEY,
rules: [
// Protect against common attacks with Arcjet Shield
shield({
mode: "LIVE", // will block requests. Use "DRY_RUN" to log only
}),
],
client: createRemoteClient({
transport: createConnectTransport({
baseUrl: defaultBaseUrl(),
httpVersion: "2",
}),
}),
});
const server = http.createServer(async function (
req: http.IncomingMessage,
res: http.ServerResponse,
) {
// Construct an object with Arcjet request details
const path = new URL(req.url || "", `http://${req.headers.host}`);
const details = {
ip: req.socket.remoteAddress,
method: req.method,
host: req.headers.host,
path: path.pathname,
headers: req.headers,
};
const decision = await aj.protect(details);
console.log(decision);
if (decision.isDenied()) {
res.writeHead(403, { "Content-Type": "application/json" });
res.end(JSON.stringify({ error: "Forbidden" }));
} else {
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify({ data: "Hello World!" }));
}
});
server.listen(8000);

Property ‘[INTERNALS]’ is missing in type

When using the Arcjet Next.js SDK you may see a warning in your editor like this:

Argument of type x is not assignable to parameter of type 'NextMiddleware'.
Types of parameters 'req' and 'request' are incompatible.
Property '[INTERNALS]' is missing in type 'import(".../next/dist/server/web/spec-extension/request").NextRequest' but required in type 'import(".../next/dist/server/web/spec-extension/request").NextRequest'.ts(2345)
request.d.ts(7, 5): '[INTERNALS]' is declared here.

This is usually caused by a mismatch between the version of Next.js you are using and the version of the Arcjet SDK. You have several options for fixing this:

  1. Update the Arcjet SDK to the latest version and update your version of Next.js to the latest version. We try to keep the SDK up to date with the latest Next.js releases so they should generally match.

  2. Add a resolution override to your package.json to force the SDK to use the same version of Next.js. For example, if you are using Next.js 14.1.4 you can add this override to your package.json to force the Arcjet SDK to use the same version:

    {
    "overrides": {
    "next": "14.1.4"
    }
    }
  3. You can ignore the warning. The warning is just a TypeScript error and does not affect the runtime behavior of your application. You can add a comment on the line that is causing the error to ignore it: // @ts-ignore

Calling protect() with no rules is deprecated

When using the Arcjet SDK you may see a warning like this:

Calling `protect()` with no rules is deprecated. Did you mean to configure the Shield rule?

Prior to the JS SDK release v1.0.0-alpha.12 we allowed empty rules and automatically configured a Shield rule for you. From v1.0.0-alpha.12 onwards you must explicitly configure the Shield rule. This allows you to choose if you want to block suspicious requests or not. We are maintaining the old behavior for a while to give you time to update your code, which is why this is warning you. Shield is still configured automatically but you should now migrate to explicitly configuring it.

Check out the Shield documentation to learn how to configure Shield rules. To restore the old behavior you can add a simple Shield rule:

import arcjet, { shield } from "@arcjet/next";
const aj = arcjet({
// Get your site key from https://app.arcjet.com
// and set it as an environment variable rather than hard coding.
// See: https://nextjs.org/docs/pages/building-your-application/configuring/environment-variables
key: process.env.ARCJET_KEY,
rules: [
// Protect against common attacks with Arcjet Shield
shield({
mode: "LIVE", // will block requests. Use "DRY_RUN" to log only
}),
],
});

Get help

We provide technical support for all Arcjet users so if you need help, email us or join our Discord.