nocobase/nocobase · error · FlowSurfaceBadRequestError

flowSurfaces addAction '${normalizedUse}' is not allowed und

Error message

flowSurfaces addAction '${normalizedUse}' is not allowed under '${input.containerUse}'

What it means

In resolveSupportedActionCatalogItem, when the request supplies `use`, the resolver looks up all catalog items registered for that use and checks which of them are allowed in the requested containerUse. If candidates exist for the use but NONE of them (regardless of package availability) is registered under that containerUse, the action/use combination is structurally invalid for that container and the resolver throws this FlowSurfaceBadRequestError before availability is even considered.

Source

Thrown at packages/plugins/@nocobase/plugin-flow-engine/src/server/flow-surfaces/catalog.ts:4184

  } = {},
) {
  const requestedType = String(input.type || '').trim();
  const normalizedUse = String(input.use || '').trim();
  let item: FlowSurfaceCatalogItem | undefined;
  if (input.containerUse) {
    assertKnownActionContainerUse({
      containerUse: input.containerUse,
      context: 'resolveAction',
    });
  }

  if (normalizedUse) {
    const useCandidates = ACTION_CATALOG_BY_USE.get(normalizedUse) || [];
    const availableUseCandidates = filterAvailableCatalogItems(useCandidates, options.enabledPackages);
    const matchedAll = getContainerScopedActionCatalogItems(useCandidates, input.containerUse);
    const matched = getContainerScopedActionCatalogItems(availableUseCandidates, input.containerUse);
    if (useCandidates.length && input.containerUse && !matchedAll.length) {
      throw new FlowSurfaceBadRequestError(
        `flowSurfaces addAction '${normalizedUse}' is not allowed under '${input.containerUse}'`,
      );
    }
    if ((matchedAll.length || useCandidates.length) && !matched.length && !availableUseCandidates.length) {
      throwUnavailableCatalogItem(useCandidates[0], {
        context: options.context || 'addAction',
        requestedUse: normalizedUse,
      });
    }
    if (matchedAll.length && !matched.length) {
      throwUnavailableCatalogItem(matchedAll[0], {
        context: options.context || 'addAction',
        requestedUse: normalizedUse,
      });
    }
    if (matched.length > 1 && !input.containerUse) {
      throw new FlowSurfaceBadRequestError(
        `flowSurfaces addAction use '${normalizedUse}' requires containerUse to resolve a public action capability`,

View on GitHub (pinned to fa42722fef)

Solutions

  1. Check the action catalog for which containerUse values the given use is registered under and pass a compatible containerUse
  2. Use `type` instead of `use` if you mean a specific public action key
  3. If you own the action registration, add the containerUse to its allowed containers in ACTION_CATALOG
  4. Verify the containerUse string for typos and that it is a known action container use

Example fix

// before
await flowSurfaces.addAction({ use: 'customize:popup', containerUse: 'filterForm' }); // not allowed under 'filterForm'
// after
await flowSurfaces.addAction({ use: 'customize:popup', containerUse: 'tableRow' }); // container that registers this use
Defensive patterns

Strategy: validation

Validate before calling

const candidates = getActionCatalogItemsByUse(use);
const allowed = candidates.filter((c) => isActionAllowedInContainer(c, containerUse));
if (!allowed.length) throw new Error(`Use '${use}' is not registered under containerUse '${containerUse}'`);

Type guard

function isUseAllowedInContainer(use, containerUse) {
  return getContainerScopedActionCatalogItems(ACTION_CATALOG_BY_USE.get(use) || [], containerUse).length > 0;
}

Try / catch

try {
  await flowSurfaces.addAction({ use, containerUse });
} catch (e) {
  if (e instanceof FlowSurfaceBadRequestError && /is not allowed under/.test(e.message)) {
    // pick a supported containerUse from the catalog
  } else throw e;
}

Prevention

When it happens

Trigger: flowSurfaces addAction with { use: '<someUse>', containerUse: '<containerUse>' } where ACTION_CATALOG_BY_USE has entries for the use but getContainerScopedActionCatalogItems finds zero items scoped to that containerUse.

Common situations: Typo or stale use value paired with a container that never supported it; copying an addAction payload from one container type (e.g. table row) to another (e.g. form) where the use is not registered; plugin that registers the action under a different containerUse than assumed.

Related errors


AI-assisted analysis of nocobase/nocobase@fa42722fef (2026-09-01). Data as JSON: /api/errors/6a1ed7bd995b8efc. Report an issue: GitHub.