koala73/worldmonitor · error

Convex unavailable

Error message

Convex unavailable

What it means

createEmbedKey needs both a Convex client and the generated Convex API reference; Promise.all resolves both and if either is null/undefined (Convex not configured or client initialization failed) this error is thrown. It signals the app's persistence backend is unavailable, not an auth or input problem.

Solutions

  1. Verify the Convex URL environment variable is set in the deployment/localhost env and restart.
  2. Ensure the ConvexProvider is mounted at the app root so getConvexClient() can resolve.
  3. Run `convex dev` / redeploy the Convex functions and confirm the generated api reference matches.
  4. Add a startup check that surfaces a clear configuration error if Convex is unset.

Example fix

// before
const [client, api] = await Promise.all([getConvexClient(), getConvexApi()]);
if (!client || !api) throw new Error('Convex unavailable');
// after
const convexUrl = import.meta.env.VITE_CONVEX_URL;
if (!convexUrl) throw new Error('VITE_CONVEX_URL is not configured');
const [client, api] = await Promise.all([getConvexClient(), getConvexApi()]);
if (!client || !api) throw new Error('Convex unavailable — check provider mounting');
Defensive patterns

Strategy: validation

Validate before calling

if (!import.meta.env.VITE_CONVEX_URL) throw new Error('Convex URL env var is not set');
const client = getConvexClient();
if (!client) throw new Error('ConvexProvider not mounted');

Type guard

const convexReady = (): boolean => getConvexClient() != null && getConvexApi() != null;

Try / catch

try {
  await createEmbedKey(name);
} catch (e) {
  if (e.message === 'Convex unavailable') {
    showError('Backend not configured — check the Convex deployment URL.');
  } else throw e;
}

Prevention

When it happens

Trigger: getConvexClient() or getConvexApi() returns null — e.g. NEXT_PUBLIC/VITE Convex URL env var missing, ConvexProvider not mounted, or client construction failed during boot.

Common situations: Deploying without the Convex deployment URL environment variable set; running locally without `convex dev`; a build that tree-shook or misconfigured the Convex provider; Convex deployment deleted or renamed.

Understand the failure class

Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of koala73/worldmonitor@7d06c8633d (2026-09-15). Data as JSON: /api/errors/3fa6fd9d83576f64. Report an issue: GitHub.

Appendix: source

Thrown at src/services/embed-keys.ts:90

 */
function embedKeyPrefix(plaintext: string): string {
  return plaintext.slice(0, 9);
}

/**
 * Create a new embed key for the current user.
 * Returns the full plaintext key (shown once) and metadata.
 */
export async function createEmbedKey(name: string): Promise<CreateEmbedKeyResult> {
  const userId = getCurrentClerkUser()?.id;
  if (!userId) throw new Error('Sign in to create an embed key.');

  const plaintext = generateEmbedKey();
  const keyPrefix = embedKeyPrefix(plaintext);
  const keyHash = await sha256Hex(plaintext);

  const [client, api] = await Promise.all([getConvexClient(), getConvexApi()]);
  if (!client || !api) throw new Error('Convex unavailable');
  if (!await waitForConvexAuthForUser(userId)) {
    throw new Error('Account changed while creating the embed key. Try again.');
  }

  const result = await settleAccountOperation(
    userId,
    'creating the embed key',
    () => client.mutation(
      (api as any).embedKeys.createEmbedKey,
      { name: name.trim(), keyPrefix, keyHash },
    ),
  );
  assertAccountStillCurrent(userId, 'creating the embed key');

  return { id: result.id, name: result.name, keyPrefix: result.keyPrefix, key: plaintext };
}

/** List all embed keys for the current user. */

View on GitHub (pinned to 7d06c8633d)