{"record":{"id":"97d329ba65fe6f21","repo":"nocobase/nocobase","slug":"chart-query-resource-is-required","errorCode":null,"errorMessage":"chart query.resource is required","messagePattern":"chart query\\.resource is required","errorType":"validation","errorClass":"FlowSurfaceBadRequestError","httpStatus":400,"severity":"error","filePath":"packages/plugins/@nocobase/plugin-flow-engine/src/server/flow-surfaces/chart-config.ts","lineNumber":657,"sourceCode":"    const collectionPathResource = normalizeChartResourceFromCollectionPath(\n      query.collectionPath,\n      'chart query.collectionPath',\n    );\n    if (!_.isEqual(resource, collectionPathResource)) {\n      throw new FlowSurfaceBadRequestError(\n        'chart query.resource and chart query.collectionPath must reference the same collection',\n      );\n    }\n    return resource;\n  }\n  if (hasOwn(query, 'resource')) {\n    return normalizeChartResource(query.resource, 'chart query.resource', options);\n  }\n  if (hasOwn(query, 'collectionPath')) {\n    return normalizeChartResourceFromCollectionPath(query.collectionPath, 'chart query.collectionPath', options);\n  }\n  if (options.required) {\n    throw new FlowSurfaceBadRequestError('chart query.resource is required');\n  }\n  return undefined;\n}\n\nfunction normalizeChartMeasure(input: any, index: number) {\n  const label = `chart query.measures[${index}]`;\n  const normalized = ensurePlainObject(input, label);\n  const field = normalizeChartQueryFieldPathValue(normalized.field, `${label}.field`, { required: true });\n  const alias = normalizeOptionalTrimmedString(normalized.alias, `${label}.alias`);\n  const aggregation = normalizeOptionalEnumValue(\n    normalized.aggregation,\n    CHART_QUERY_AGGREGATION_SET,\n    `${label}.aggregation`,\n  );\n  return buildDefinedObject({\n    field,\n    aggregation,\n    alias: alias || (Array.isArray(field) && field.length > 1 ? aliasOfFieldValue(field) : undefined),","sourceCodeStart":639,"sourceCodeEnd":675,"githubUrl":"https://github.com/nocobase/nocobase/blob/fa42722fefe44265490dff2c27d79e2882bce4fa/packages/plugins/@nocobase/plugin-flow-engine/src/server/flow-surfaces/chart-config.ts#L639-L675","documentation":"normalizeMergedChartResource is the top-level resolver for a chart query's collection reference. If the query has neither a resource key nor a collectionPath key and options.required is set, it throws FlowSurfaceBadRequestError 'chart query.resource is required'.","triggerScenarios":"Any strictly-normalized chart query operation (creating/updating a chart whose query must target a collection) with a query object lacking both resource and collectionPath.","commonSituations":"New charts before collection selection; API clients sending bare query bodies; payloads where the fields were nested one level deeper than the schema expects.","solutions":["Add query.resource: { collectionName, dataSourceKey? } to the chart query","Or add query.collectionPath: [dataSourceKey, collectionName]","Fix payload nesting so resource/collectionPath sit directly on the query object (hasOwn checks top-level keys only)"],"exampleFix":"// before\n{ query: { filter: {}, measures: [] } }\n// after\n{ query: { resource: { collectionName: 'orders', dataSourceKey: 'main' }, filter: {}, measures: [] } }","handlingStrategy":"validation","validationCode":"function assertQueryHasCollection(query = {}) {\n  const hasResource = Object.prototype.hasOwnProperty.call(query, 'resource') && query.resource != null;\n  const hasPath = Object.prototype.hasOwnProperty.call(query, 'collectionPath') && query.collectionPath != null;\n  if (!hasResource && !hasPath) throw new Error('chart query.resource is required');\n}","typeGuard":"function hasChartResource(q: unknown): q is { resource: { collectionName: string; dataSourceKey?: string } } {\n  return typeof q === 'object' && q !== null && (q as any).resource != null && typeof (q as any).resource.collectionName === 'string';\n}","tryCatchPattern":"try {\n  await api.saveChartQuery(query);\n} catch (err) {\n  if (err instanceof FlowSurfaceBadRequestError && err.message === 'chart query.resource is required') {\n    // open collection selection UI, then attach query.resource and retry\n  }\n  throw err;\n}","preventionTips":["Always attach resource (or collectionPath) directly on the query object — nested fields are invisible to hasOwn checks","Block save/execute actions until a collection is chosen in the builder","Add an end-to-end payload schema test covering chart create/update paths"],"tags":["validation","required-field","chart-config","bad-request"],"backgroundTag":"missing-required-argument","analyzedSha":"fa42722fefe44265490dff2c27d79e2882bce4fa","analyzedAt":"2026-09-01T00:54:31.202Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}