{"record":{"id":"0320e31cdddc352d","repo":"nocobase/nocobase","slug":"label-is-required","errorCode":null,"errorMessage":"${label} is required","messagePattern":"(.+?) 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":482,"sourceCode":"  if (_.isUndefined(input) || _.isNull(input)) {\n    return undefined;\n  }\n  return normalizeInteger(input, label, options);\n}\n\nfunction normalizeEnumValue(\n  input: any,\n  allowed: Set<string>,\n  label: string,\n  options: {\n    fallback?: string;\n  } = {},\n) {\n  if (_.isUndefined(input) || _.isNull(input) || String(input).trim() === '') {\n    if (!_.isUndefined(options.fallback)) {\n      return options.fallback;\n    }\n    throw new FlowSurfaceBadRequestError(`${label} is required`);\n  }\n  const normalized = String(input).trim();\n  if (!allowed.has(normalized)) {\n    throw new FlowSurfaceBadRequestError(`${label} is invalid: ${normalized}`);\n  }\n  return normalized;\n}\n\nfunction normalizeOptionalEnumValue(input: any, allowed: Set<string>, label: string) {\n  if (_.isUndefined(input) || _.isNull(input) || String(input).trim() === '') {\n    return undefined;\n  }\n  return normalizeEnumValue(input, allowed, label);\n}\n\nfunction normalizeFieldPathValue(input: any, label: string, options: { required?: boolean } = {}) {\n  if (_.isUndefined(input) || _.isNull(input)) {\n    if (options.required) {","sourceCodeStart":464,"sourceCodeEnd":500,"githubUrl":"https://github.com/nocobase/nocobase/blob/fa42722fefe44265490dff2c27d79e2882bce4fa/packages/plugins/@nocobase/plugin-flow-engine/src/server/flow-surfaces/chart-config.ts#L464-L500","documentation":"normalizeEnumValue validates a labeled value against an allowed Set of strings. When the value is undefined, null, or whitespace-only and no fallback option is configured, it throws FlowSurfaceBadRequestError stating the field is required. Callers like inferQueryMode/inferVisualMode use it to resolve chart query/visual modes.","triggerScenarios":"Omitting a required enum field (e.g. query mode or visual type) in chart config where the specific normalizeEnumValue call has no fallback; passing '' or '   ' for such a field.","commonSituations":"Hand-written config missing newer required fields after an upgrade; form submit leaving a select empty; template rendering with a blank variable.","solutions":["Set the field to one of the allowed values (check the surrounding schema/docs for valid modes, e.g. sql vs aggregation)","Supply a non-empty string at the config source (env, JSON, form) so the value resolves","If a default should apply, set the value explicitly to the intended default rather than leaving it blank"],"exampleFix":"// before\n{ \"queryMode\": \"\" }\n// after\n{ \"queryMode\": \"sql\" }","handlingStrategy":"validation","validationCode":"const QUERY_MODES = new Set(['sql','aggregation']);\nif (!config.queryMode || !String(config.queryMode).trim()) {\n  config.queryMode = 'sql'; // or throw in your own validation\n}","typeGuard":"const isFilledEnum = (v: unknown, allowed: Set<string>): v is string => typeof v === 'string' && allowed.has(v.trim());","tryCatchPattern":"try { await submitChartConfig(cfg); } catch (e) { if (e instanceof FlowSurfaceBadRequestError && /is required$/.test(e.message)) { /* prompt user to select the missing mode field */ } else { throw e; } }","preventionTips":["Give enum selects non-empty defaults in forms","Add required-field checks to your own pre-submit validation","After plugin upgrades, audit configs for newly required fields"],"tags":["validation","enum","required-field"],"backgroundTag":"missing-required-argument","analyzedSha":"fa42722fefe44265490dff2c27d79e2882bce4fa","analyzedAt":"2026-09-01T00:54:31.202Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}