lobehub/lobehub · warning · TRPCError

NOT_FOUND

NOT_FOUND

Error message

Credential not found: ${input.key}

What it means

Deliberate validation throw in `creds.getByKey` (creds.ts:229). Unlike the other creds errors, this is `NOT_FOUND`, not `INTERNAL_SERVER_ERROR`, and it is thrown on purpose when no credential in `creds.list()` matches `input.key`. It is re-thrown unchanged by the catch block (which has `if (error instanceof TRPCError) throw error;`), so the client receives a clean 404 with the offending key in the message.

Source

Thrown at apps/server/src/routers/lambda/market/creds.ts:229

  // Get single credential by key (optionally with decrypted values)
  getByKey: credsManageProcedure
    .input(
      z.object({
        decrypt: z.boolean().optional(),
        key: z.string(),
      }),
    )
    .query(async ({ ctx, input }) => {
      log('getByKey input: %O', input);

      try {
        // First find the credential by key from the list
        const listResult = await ctx.marketService.market.creds.list();
        const cred = listResult.data?.find((c) => c.key === input.key);

        if (!cred) {
          throw new TRPCError({
            code: 'NOT_FOUND',
            message: `Credential not found: ${input.key}`,
          });
        }

        // Then get the full credential with optional decryption
        const result = await ctx.marketService.market.creds.get(cred.id, {
          decrypt: input.decrypt,
        });
        log('getByKey success: key=%s, id=%d', input.key, cred.id);
        return result;
      } catch (error) {
        if (error instanceof TRPCError) throw error;
        log('getByKey error: %O', error);
        throw new TRPCError({
          cause: error,
          code: 'INTERNAL_SERVER_ERROR',
          message: 'Failed to get credential by key',

View on GitHub (pinned to 10f24d7ade)

Solutions

  1. Confirm the key exists via `list` (or the UI) before calling `getByKey`.
  2. Treat `NOT_FOUND` on the client as 'credential missing' and prompt the user to (re)create it, not as a crash.
  3. Avoid hardcoding keys — store references to credential ids returned by create/list.
  4. If the key is environment-specific, namespace it (e.g. `prod:openai_key`) and validate against the active environment.

Example fix

// before — caller has no pre-check
const cred = await trpc.market.creds.getByKey.query({ key: 'openai_key' });
// after — verify existence via list, handle 404 gracefully
const list = await trpc.market.creds.list.query();
if (!list.data?.some((c) => c.key === 'openai_key')) {
  throw new Error('OpenAI credential is not configured. Please add it in Settings.');
}
const cred = await trpc.market.creds.getByKey.query({ key: 'openai_key' });
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check the key exists before calling getByKey
const list = await trpc.market.creds.list.query();
if (!list.data?.some((c) => c.key === key)) {
  throw new Error(`Credential '${key}' is not configured.`);
}

Type guard

function isCredKey(v: unknown): v is string { return typeof v === 'string' && v.length > 0 && v.length <= 100; }

Try / catch

try {
  return await trpc.market.creds.getByKey.query({ key });
} catch (e) {
  const err = e as { data?: { code?: string } };
  if (err.data?.code === 'NOT_FOUND') {
    // prompt user to create the credential instead of crashing
    throw new Error(`Credential '${key}' is missing. Please add it in Settings.`);
  }
  throw e;
}

Prevention

When it happens

Trigger: Caller passes a `key` that doesn't exist in the user's credentials; key was deleted between a list call and the getByKey call; typo in the key; key belongs to a different user/workspace scope.

Common situations: Hardcoded/legacy key reference after the credential was renamed; race between delete and read; key copied from a different environment (dev vs prod).

Related errors


AI-assisted analysis of lobehub/lobehub@10f24d7ade (2026-08-12). Data as JSON: /api/errors/8133b26e1148d7e0. Report an issue: GitHub.