{"record":{"id":"b63df646cbdbd022","repo":"langfuse/langfuse","slug":"missing-projectid-in-scope-are-you-using-an-organ","errorCode":null,"errorMessage":"Missing projectId in scope. Are you using an organization key?","messagePattern":"Missing projectId in scope\\. Are you using an organization key\\?","errorType":"exception","errorClass":"UnauthorizedError","httpStatus":401,"severity":"error","filePath":"web/src/features/datasets/server/publicDatasetService.ts","lineNumber":778,"sourceCode":" * dataset_run_items ClickHouse table, so the full createDatasetRunItemForApi\n * flow has nothing to persist. The experiment runner still calls POST\n * /dataset-run-items per item and expects a dataset run id it can reuse as the\n * experiment id across the whole run, so we resolve the item's dataset and\n * return a stable experiment id derived from (projectId, datasetId, runName).\n *\n * In v4 the trace ↔ experiment link is established through OTel experiment span\n * attributes instead, so beyond the dataset-item lookup (needed for datasetId\n * and to 404 on genuinely missing items) we skip every legacy side effect:\n * the observation→trace lookup, ClickHouse ingestion, and the eval enqueue.\n */\nexport const buildStableDatasetRunItemResponseEventsOnly = async ({\n  body,\n  auth,\n}: Pick<CreateDatasetRunItemInput, \"body\" | \"auth\">) => {\n  const projectId = auth.scope.projectId;\n\n  if (!projectId) {\n    throw new UnauthorizedError(\n      \"Missing projectId in scope. Are you using an organization key?\",\n    );\n  }\n\n  const datasetItem = await getDatasetItemById({\n    projectId,\n    datasetItemId: body.datasetItemId,\n    status: \"ACTIVE\",\n    version: body.datasetVersion ?? undefined,\n  });\n\n  if (!datasetItem) {\n    throw new LangfuseNotFoundError(\"Dataset item not found\");\n  }\n\n  const experimentId = createStableExperimentId({\n    projectId,\n    datasetId: datasetItem.datasetId,","sourceCodeStart":760,"sourceCodeEnd":796,"githubUrl":"https://github.com/langfuse/langfuse/blob/59d92c7cf365150d10b753b5a0d1708902a2ed60/web/src/features/datasets/server/publicDatasetService.ts#L760-L796","documentation":"The dataset run item endpoints resolve the target project from auth.scope.projectId; organization-scoped API keys have no single project, so the scope is undefined and the request is rejected as unauthorized before any data access.","triggerScenarios":"POST /api/public/dataset-run-items using an organization-level API key (pk-org-.../sk-org-...) instead of a project-scoped key.","commonSituations":"Adopting the new org key format and reusing it for dataset ingestion; CI scripts updated to org keys while the SDK endpoint still requires a project.","solutions":["Use a project-scoped API key (pk-org-.../sk-org-... created for a specific project) for dataset run item calls","If org keys must be used, route to an endpoint variant that accepts an explicit project parameter, if available","Check the key type in Project Settings > API Keys before wiring ingestion"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if (!process.env.LANGFUSE_PUBLIC_KEY?.startsWith('pk-org-')) { /* project key ok */ } else throw new Error('Use a project-scoped key for dataset-run-items');","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep a dedicated project-scoped key for dataset ingestion","Document which endpoints require project scope when using org keys"],"tags":["auth","api-key","organization-scope","public-api"],"backgroundTag":"missing-scope-in-token","analyzedSha":"59d92c7cf365150d10b753b5a0d1708902a2ed60","analyzedAt":"2026-08-27T22:22:00.402Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}