diff --git a/.changeset/kind-crabs-unite.md b/.changeset/kind-crabs-unite.md
new file mode 100644
index 00000000000..da62a4f65be
--- /dev/null
+++ b/.changeset/kind-crabs-unite.md
@@ -0,0 +1,5 @@
+---
+'@clerk/nextjs': patch
+---
+
+Gracefully handle failure to create keyless.
diff --git a/packages/nextjs/src/app-router/client/ClerkProvider.tsx b/packages/nextjs/src/app-router/client/ClerkProvider.tsx
index 57b3f7db58f..9b12d1c84a6 100644
--- a/packages/nextjs/src/app-router/client/ClerkProvider.tsx
+++ b/packages/nextjs/src/app-router/client/ClerkProvider.tsx
@@ -123,11 +123,11 @@ const NextClientClerkProvider = (props: NextClerkProviderProps) => {
);
};
-export const ClientClerkProvider = (props: NextClerkProviderProps) => {
- const { children, ...rest } = props;
+export const ClientClerkProvider = (props: NextClerkProviderProps & { disableKeyless?: boolean }) => {
+ const { children, disableKeyless = false, ...rest } = props;
const safePublishableKey = mergeNextClerkPropsWithEnv(rest).publishableKey;
- if (safePublishableKey || !canUseKeyless) {
+ if (safePublishableKey || !canUseKeyless || disableKeyless) {
return {children};
}
diff --git a/packages/nextjs/src/app-router/client/keyless-creator-reader.tsx b/packages/nextjs/src/app-router/client/keyless-creator-reader.tsx
index 6b575fe0781..fb986f74bbc 100644
--- a/packages/nextjs/src/app-router/client/keyless-creator-reader.tsx
+++ b/packages/nextjs/src/app-router/client/keyless-creator-reader.tsx
@@ -19,8 +19,8 @@ export const KeylessCreatorOrReader = (props: NextClerkProviderProps) => {
return React.cloneElement(children, {
key: state?.publishableKey,
publishableKey: state?.publishableKey,
- __internal_claimKeylessApplicationUrl: state?.claimUrl,
- __internal_copyInstanceKeysUrl: state?.apiKeysUrl,
+ __internal_keyless_claimKeylessApplicationUrl: state?.claimUrl,
+ __internal_keyless_copyInstanceKeysUrl: state?.apiKeysUrl,
__internal_bypassMissingPublishableKey: true,
} as any);
};
diff --git a/packages/nextjs/src/app-router/keyless-actions.ts b/packages/nextjs/src/app-router/keyless-actions.ts
index 1512a85aa24..cd4ff10e23d 100644
--- a/packages/nextjs/src/app-router/keyless-actions.ts
+++ b/packages/nextjs/src/app-router/keyless-actions.ts
@@ -3,6 +3,7 @@ import type { AccountlessApplication } from '@clerk/backend';
import { cookies, headers } from 'next/headers';
import { redirect, RedirectType } from 'next/navigation';
+import { errorThrower } from '../server/errorThrower';
import { detectClerkMiddleware } from '../server/headers-utils';
import { getKeylessCookieName } from '../server/keyless';
import { canUseKeyless } from '../utils/feature-flags';
@@ -35,9 +36,10 @@ export async function createOrReadKeylessAction(): Promise m.createOrReadKeyless());
+ const result = await import('../server/keyless-node.js').then(m => m.createOrReadKeyless()).catch(() => null);
if (!result) {
+ errorThrower.throwMissingPublishableKeyError();
return null;
}
diff --git a/packages/nextjs/src/app-router/server/ClerkProvider.tsx b/packages/nextjs/src/app-router/server/ClerkProvider.tsx
index 02e039fdc76..96db748ec7d 100644
--- a/packages/nextjs/src/app-router/server/ClerkProvider.tsx
+++ b/packages/nextjs/src/app-router/server/ClerkProvider.tsx
@@ -85,7 +85,9 @@ export async function ClerkProvider(
if (shouldRunAsKeyless) {
// NOTE: Create or read keys on every render. Usually this means only on hard refresh or hard navigations.
- const newOrReadKeys = await import('../../server/keyless-node.js').then(mod => mod.createOrReadKeyless());
+ const newOrReadKeys = await import('../../server/keyless-node.js')
+ .then(mod => mod.createOrReadKeyless())
+ .catch(() => null);
const { keylessLogger, createConfirmationMessage, createKeylessModeMessage } = await import(
'../../server/keyless-log-cache.js'
);
@@ -142,6 +144,18 @@ export async function ClerkProvider(
output = {clientProvider};
}
+ } else {
+ // When case keyless should run, but keys are not available, then fallback to throwing for missing keys
+ output = (
+
+ {children}
+
+ );
}
}
diff --git a/packages/nextjs/src/server/keyless-node.ts b/packages/nextjs/src/server/keyless-node.ts
index f83f88028f2..8cedd257b76 100644
--- a/packages/nextjs/src/server/keyless-node.ts
+++ b/packages/nextjs/src/server/keyless-node.ts
@@ -123,7 +123,7 @@ const isFileWritingLocked = () => {
return isCreatingFile || existsSync(CLERK_LOCK);
};
-async function createOrReadKeyless(): Promise {
+async function createOrReadKeyless(): Promise {
const { writeFileSync, mkdirSync } = safeNodeRuntimeFs();
/**
@@ -131,7 +131,7 @@ async function createOrReadKeyless(): Promise null);
- writeFileSync(CONFIG_PATH, JSON.stringify(accountlessApplication), {
- encoding: 'utf8',
- mode: '0777',
- flag: 'w',
- });
+ if (accountlessApplication) {
+ writeFileSync(CONFIG_PATH, JSON.stringify(accountlessApplication), {
+ encoding: 'utf8',
+ mode: '0777',
+ flag: 'w',
+ });
- // TODO-KEYLESS: Add link to official documentation.
- const README_NOTIFICATION = `
+ // TODO-KEYLESS: Add link to official documentation.
+ const README_NOTIFICATION = `
## DO NOT COMMIT
This directory is auto-generated from \`@clerk/nextjs\` because you are running in Keyless mode. Avoid committing the \`.clerk/\` directory as it includes the secret key of the unclaimed instance.
`;
- writeFileSync(README_PATH, README_NOTIFICATION, {
- encoding: 'utf8',
- mode: '0777',
- flag: 'w',
- });
-
+ writeFileSync(README_PATH, README_NOTIFICATION, {
+ encoding: 'utf8',
+ mode: '0777',
+ flag: 'w',
+ });
+ }
/**
* Clean up locks.
*/