{"record":{"id":"6e6ced2969708a2a","repo":"langfuse/langfuse","slug":"project-not-found","errorCode":null,"errorMessage":"Project not found","messagePattern":"Project not found","errorType":"exception","errorClass":"LangfuseNotFoundError","httpStatus":404,"severity":"error","filePath":"web/src/pages/api/public/integrations/blob-storage/index.ts","lineNumber":155,"sourceCode":"      plan: authCheck.scope.plan,\n      entitlement: \"scheduled-blob-exports\",\n    })\n  ) {\n    throw new ForbiddenError(\n      \"scheduled-blob-exports entitlement required for this feature.\",\n    );\n  }\n\n  // Validate request body\n  const validatedData = CreateBlobStorageIntegrationRequest.parse(req.body);\n\n  // Check if the project exists and belongs to the organization\n  const project = await prisma.project.findUnique({\n    where: { id: validatedData.projectId },\n    select: { id: true, orgId: true, createdAt: true },\n  });\n  if (!project || project.orgId !== authCheck.scope.orgId) {\n    throw new LangfuseNotFoundError(\"Project not found\");\n  }\n\n  const internalExportSource =\n    validatedData.exportSource != null\n      ? toInternalExportSource(validatedData.exportSource)\n      : undefined;\n\n  // Feeds both write-time gates: the legacy upsert gate needs the row's\n  // createdAt when exportSource is provided; the enriched gate needs the\n  // persisted exportSource when it is omitted (partial PUT), so a stale\n  // enriched value is rejected.\n  const existingIntegration = await prisma.blobStorageIntegration.findUnique({\n    where: { projectId: validatedData.projectId },\n    select: { createdAt: true, exportSource: true },\n  });\n\n  // Explicit sources must pass every check; an omitted source keeps the\n  // persisted one, capability-checked only, and a create falls back to the","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/langfuse/langfuse/blob/59d92c7cf365150d10b753b5a0d1708902a2ed60/web/src/pages/api/public/integrations/blob-storage/index.ts#L137-L173","documentation":"The projectId in the request body either does not exist or does not belong to the organization of the API key. The endpoint looks up the project and compares orgId to the token scope's orgId, throwing 404 to avoid leaking project existence.","triggerScenarios":"PUT /api/public/integrations/blob-storage with a projectId from another organization, a deleted project, or a typo'd id.","commonSituations":"Hardcoded project ids copied between environments (staging id used against production), or after a project was deleted.","solutions":["List the org's projects (GET /api/public/projects) and use the exact projectId from the same org as the API key","Confirm the project still exists in the UI"],"exampleFix":"// before\nbody: JSON.stringify({ projectId: 'proj-from-staging', ... })\n\n// after\nconst projects = await listProjects(orgAuth);\nbody: JSON.stringify({ projectId: projects.find(p => p.name === 'prod').id, ... })","handlingStrategy":"validation","validationCode":"const projects = await langfusePublicApi.projects.list();\nconst project = projects.data.find(p => p.id === bodyProjectId);\nif (!project) throw new Error('projectId not in this org');","typeGuard":null,"tryCatchPattern":"catch (e) { if (e.status === 404) retryAfterProjectSync(); throw e; }","preventionTips":["Resolve project ids dynamically per environment instead of hardcoding"],"tags":["not-found","project-id","blob-storage"],"backgroundTag":"resource-not-found","analyzedSha":"59d92c7cf365150d10b753b5a0d1708902a2ed60","analyzedAt":"2026-08-27T22:22:00.402Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}