lobehub/lobehub · error · TRPCError
NOT_FOUND
NOT_FOUND
Error message
Knowledge base not found
What it means
Thrown by file.createFile (file.ts:202) when the upload is workspace-scoped (ctx.workspaceId set) and carries a knowledgeBaseId, but knowledgeBaseModel.findById(input.knowledgeBaseId) returns null. The knowledge base must exist before the upload's visibility-precedence logic can inherit its visibility. The check fires before any size validation or transaction.
Source
Thrown at apps/server/src/routers/lambda/file.ts:202
// Resolve parentId if it's a slug
let resolvedParentId = input.parentId;
let parentVisibility: 'private' | 'public' | undefined;
if (input.parentId) {
const docBySlug = await ctx.documentModel.findBySlug(input.parentId);
if (docBySlug) {
resolvedParentId = docBySlug.id;
parentVisibility = docBySlug.visibility;
} else {
const docById = await ctx.documentModel.findById(input.parentId);
if (docById) parentVisibility = docById.visibility;
}
}
let knowledgeBaseVisibility: 'private' | 'public' | undefined;
if (ctx.workspaceId && input.knowledgeBaseId) {
const knowledgeBase = await ctx.knowledgeBaseModel.findById(input.knowledgeBaseId);
if (!knowledgeBase) {
throw new TRPCError({ code: 'NOT_FOUND', message: 'Knowledge base not found' });
}
knowledgeBaseVisibility = knowledgeBase.visibility;
}
// Visibility precedence (workspace mode only — personal mode ignores the
// column entirely):
// 1. A library upload always uses the knowledge base visibility.
// 2. Otherwise an explicit caller value wins.
// 3. Otherwise inherit the parent document's visibility so a file
// uploaded inside a private folder stays private.
// 4. Otherwise default top-level uploads to 'private' so new content
// starts in the creator's private space (mirrors the Pages spec).
const resolvedVisibility: 'private' | 'public' | undefined = ctx.workspaceId
? (knowledgeBaseVisibility ?? input.visibility ?? parentVisibility ?? 'private')
: undefined;
let actualSize = input.size;
try {View on GitHub (pinned to 10f24d7ade)
Solutions
- Re-fetch the knowledge base list for the active workspace and use a current knowledgeBaseId.
- If the upload does not target a knowledge base, omit knowledgeBaseId entirely rather than passing a stale id.
- Drop the KB reference from the UI when the KB list no longer contains it.
Example fix
// before
await trpc.file.createFile.mutate({ ..., knowledgeBaseId: staleKbId });
// after
const kbs = await trpc.knowledgeBase.list.query();
const kb = kbs.find((k) => k.id === staleKbId);
if (!kb) {
showToast('Select a knowledge base');
return;
}
await trpc.file.createFile.mutate({ ..., knowledgeBaseId: kb.id }); Defensive patterns
Strategy: validation
Validate before calling
const kbs = await trpc.knowledgeBase.list.query();
if (!kbs.some((k) => k.id === knowledgeBaseId)) {
showToast('Select a valid knowledge base');
return;
}
await trpc.file.createFile.mutate({ ..., knowledgeBaseId }); Type guard
function isKnowledgeBaseMissing(err: unknown): boolean {
return (
typeof err === 'object' &&
err !== null &&
(err as { data?: { code?: string } }).data?.code === 'NOT_FOUND'
);
} Try / catch
try {
await trpc.file.createFile.mutate({ ..., knowledgeBaseId });
} catch (err) {
if (isTrpcCode(err, 'NOT_FOUND')) {
refreshKnowledgeBases();
return;
}
throw err;
} Prevention
- Omit knowledgeBaseId when the upload is not targeting a KB rather than passing a stale id.
- Re-fetch the KB list when the upload dialog opens.
- Invalidate cached KB ids after a KB is deleted or moved.
When it happens
Trigger: Uploading a file into a knowledge base that was deleted, belongs to a different workspace, or whose id is wrong/stale. The lookup is by id only, so an id from another workspace fails the same way.
Common situations: Knowledge base deleted while the upload dialog was open; id copied from another workspace; upload triggered from a cached KB picker after the KB was moved.
Related errors
AI-assisted analysis of lobehub/lobehub@10f24d7ade (2026-08-12).
Data as JSON: /api/errors/3d5f16e943c9a037.
Report an issue: GitHub.