{"record":{"id":"191d4d7e710ddd83","repo":"nocobase/nocobase","slug":"flowsurfaces-addblock-only-supports-registered-blo","errorCode":null,"errorMessage":"flowSurfaces addBlock only supports registered block types/uses","messagePattern":"flowSurfaces addBlock only supports registered block types/uses","errorType":"validation","errorClass":"FlowSurfaceBadRequestError","httpStatus":400,"severity":"error","filePath":"packages/plugins/@nocobase/plugin-flow-engine/src/server/flow-surfaces/catalog.ts","lineNumber":4134,"sourceCode":"export function resolveSupportedBlockCatalogItem(\n  input: {\n    type?: string;\n    use?: string;\n    containerUse?: string;\n  },\n  options: {\n    context?: string;\n    enabledPackages?: ReadonlySet<string>;\n    requireCreateSupported?: boolean;\n    skipContainerValidation?: boolean;\n  } = {},\n) {\n  const item =\n    (input.type ? BLOCK_CATALOG_BY_KEY.get(String(input.type).trim()) : undefined) ||\n    (input.use ? BLOCK_CATALOG_BY_USE.get(String(input.use).trim()) : undefined);\n\n  if (!item) {\n    throw new FlowSurfaceBadRequestError(`flowSurfaces addBlock only supports registered block types/uses`);\n  }\n  if (!isCatalogItemAvailable(item, options.enabledPackages)) {\n    throwUnavailableCatalogItem(item, {\n      context: options.context || 'addBlock',\n      requestedType: input.type,\n      requestedUse: input.use,\n    });\n  }\n  if (!options.skipContainerValidation && !isBlockAllowedInContainer(item, input.containerUse)) {\n    throw new FlowSurfaceBadRequestError(\n      `flowSurfaces addBlock '${input.type || input.use || item.key}' is not allowed under '${\n        input.containerUse || 'unknown'\n      }'`,\n    );\n  }\n  if (options.requireCreateSupported && item.createSupported === false) {\n    throw new FlowSurfaceBadRequestError(`flowSurfaces addBlock does not support creating '${item.key}' yet`);\n  }","sourceCodeStart":4116,"sourceCodeEnd":4152,"githubUrl":"https://github.com/nocobase/nocobase/blob/fa42722fefe44265490dff2c27d79e2882bce4fa/packages/plugins/@nocobase/plugin-flow-engine/src/server/flow-surfaces/catalog.ts#L4116-L4152","documentation":"resolveBlockCatalogItem (catalog.ts:~4134) resolves addBlock requests by looking up input.type in BLOCK_CATALOG_BY_KEY or input.use in BLOCK_CATALOG_BY_USE. If neither lookup finds a registered item — the type/use is unknown, misspelled, or not part of the flowSurfaces block catalog — the server rejects the request because only registered block types/uses can be added.","triggerScenarios":"Calling the addBlock flowSurfaces operation with a type string not in the block catalog (typo, custom block never registered, casing mismatch) or with a use that no registered block declares; omitting both type and use so both lookups are undefined.","commonSituations":"Hand-written automation/API scripts using block names from a different NocoBase version's catalog; client code referencing a block contributed by a plugin that registers under a different use; renamed/removed block types after an upgrade; sending a raw collection name instead of a registered block type.","solutions":["Look up the exact registered block key/use in the flowSurfaces block catalog (BLOCK_CATALOG) and use it verbatim.","Fix typos and casing in input.type or input.use.","If the block comes from a plugin, enable that plugin so its items are registered in the catalog.","If both fields are being dropped, verify the client actually sends type or use in the addBlock payload.","After a version upgrade, refresh any stored configs referencing old block type names."],"exampleFix":"// before\naddBlock({ type: 'markdown ' /* unknown key */ });\n// after\naddBlock({ type: 'markdown' }); // exact registered block key, trimmed","handlingStrategy":"type-guard","validationCode":"// validate against the client-side copy of the block catalog before sending\nconst BLOCK_KEYS = new Set(['markdown', /* ...registered block keys */]);\nfunction canAddBlock(input: { type?: string; use?: string }) {\n  return Boolean(input.type && BLOCK_KEYS.has(String(input.type).trim())) || Boolean(input.use && BLOCK_KEYS.has(String(input.use).trim()));\n}","typeGuard":"function isRegisteredBlockKey(k: string | undefined, catalog: ReadonlySet<string>): k is string {\n  return typeof k === 'string' && catalog.has(k.trim());\n}","tryCatchPattern":"try {\n  addBlockItem(input);\n} catch (e) {\n  if (e instanceof FlowSurfaceBadRequestError && /only supports registered block types/.test(e.message)) {\n    // fetch the current block catalog and pick a valid type/use\n    const catalog = await getBlockCatalog();\n    console.error(`Unknown block type/use '${input.type || input.use}'. Valid:`, [...catalog].join(', '));\n  } else throw e;\n}","preventionTips":["Source block type/use constants from the served catalog, never free-text strings.","Trim and normalize keys exactly as the server does before sending.","After flow-engine upgrades, re-validate stored block type names against the new catalog."],"tags":["flow-engine","validation","catalog"],"backgroundTag":"unknown-catalog-item","analyzedSha":"fa42722fefe44265490dff2c27d79e2882bce4fa","analyzedAt":"2026-09-01T00:54:31.202Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}