{"record":{"id":"ecc18a24549bd5f2","repo":"nocobase/nocobase","slug":"datasource-values-datasourcekey-not-found","errorCode":null,"errorMessage":"dataSource ${values.dataSourceKey} not found","messagePattern":"dataSource (.+?) not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/plugins/@nocobase/plugin-data-source-manager/src/server/services/external-field-apply.ts","lineNumber":194,"sourceCode":"    .collectionManager.getCollection(values.collectionName)\n    .getField(values.name)?.options;\n}\n\nexport async function applyExternalFieldDefinition(\n  ctx,\n  rawValues: any,\n  defaults: {\n    dataSourceKey?: string;\n    collectionName?: string;\n  } = {},\n) {\n  const values = normalizeExternalFieldInput(rawValues, defaults);\n\n  validateExternalRelationField(values);\n\n  const dataSource = ctx.app.dataSourceManager.dataSources.get(values.dataSourceKey);\n  if (!dataSource) {\n    throw new Error(`dataSource ${values.dataSourceKey} not found`);\n  }\n  const collection = dataSource.collectionManager.getCollection(values.collectionName);\n  if (!collection) {\n    throw new Error(`collection ${values.collectionName} not found in dataSource ${values.dataSourceKey}`);\n  }\n\n  const repository = ctx.app.db.getRepository('dataSourcesFields');\n  const filter = {\n    name: values.name,\n    collectionName: values.collectionName,\n    dataSourceKey: values.dataSourceKey,\n  };\n  const existing = await repository.findOne({ filter });\n\n  if (existing) {\n    await repository.update({\n      filter,\n      values,","sourceCodeStart":176,"sourceCodeEnd":212,"githubUrl":"https://github.com/nocobase/nocobase/blob/fa42722fefe44265490dff2c27d79e2882bce4fa/packages/plugins/@nocobase/plugin-data-source-manager/src/server/services/external-field-apply.ts#L176-L212","documentation":"applyExternalFieldDefinition looks up the data source by key in ctx.app.dataSourceManager.dataSources after validation and throws when it is not registered. Unlike the list action, there is no loading-state handling here — an unregistered key (never created, misconfigured, or its registration failed) results in this error before any field work happens.","triggerScenarios":"Calling fields:apply / applyExternalFieldDefinition with values.dataSourceKey (or defaults.dataSourceKey) that is absent from dataSourceManager.dataSources — e.g. 'mysql2' when only 'main' is registered, or a key used before its data source finishes loading/registering at app init.","commonSituations":"Server-side scripts running during app bootstrap before external sources register; typo'd keys in migration/import scripts; data source deleted or its driver plugin disabled while automation still targets it; environment-specific keys (prod vs staging) hardcoded.","solutions":["Verify the key exists: check ctx.app.dataSourceManager.dataSources keys or the dataSources collection, and fix the dataSourceKey in the call.","Run the apply after app startup completes and external data sources are loaded, not during bootstrap.","Re-enable/reinstall the data source plugin or recreate the data source if it was removed."],"exampleFix":"// before\nawait applyExternalFieldDefinition(ctx, values, { dataSourceKey: 'mysql2' });  // not registered\n// after\nconst key = [...ctx.app.dataSourceManager.dataSources.keys()].find((k) => k.includes('mysql'));\nawait applyExternalFieldDefinition(ctx, values, { dataSourceKey: key });","handlingStrategy":"type-guard","validationCode":"function assertDataSourceRegistered(app: any, key: string) {\n  if (!app.dataSourceManager.dataSources.has(key)) {\n    throw new Error(`dataSource '${key}' not registered; known keys: ${[...app.dataSourceManager.dataSources.keys()].join(', ')}`);\n  }\n}","typeGuard":"function getRegisteredDataSource(app: any, key: unknown) {\n  const ds = typeof key === 'string' ? app.dataSourceManager.dataSources.get(key) : undefined;\n  return ds ?? null; // null means the apply call would throw — resolve key first\n}","tryCatchPattern":"try {\n  await applyExternalFieldDefinition(ctx, values, defaults);\n} catch (e) {\n  if (/^dataSource .* not found$/.test(e.message)) {\n    const keys = [...ctx.app.dataSourceManager.dataSources.keys()];\n    throw new Error(`dataSourceKey '${values.dataSourceKey}' unregistered. Available: ${keys.join(', ')}. Is the app fully started?`, { cause: e });\n  }\n  throw e;\n}","preventionTips":["Only run external field applies after app startup completes (await app.ready() / post-load hooks).","Resolve keys dynamically from dataSourceManager.dataSources instead of hardcoding environment-specific keys.","Re-check registrations after enabling/disabling data source plugins."],"tags":["data-source","not-found","external-data-source","nocobase"],"backgroundTag":"resource-not-found","analyzedSha":"fa42722fefe44265490dff2c27d79e2882bce4fa","analyzedAt":"2026-09-01T00:54:31.202Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}