Apply-blueprint栈溢出问题反馈

使用 nb api flow-surfaces apply-blueprint API 创建包含深层 belongsTo 关联链的集合页面时,系统报错 “Maximum call stack size exceeded”(栈溢出),导致无法通过 API 自动创建页面。

错误信息

{
  "errors": [{
    "message": "Maximum call stack size exceeded",
    "type": "internal_error",
    "code": "FLOW_SURFACE_INTERNAL_ERROR",
    "status": 500
  }]
}
## 影响
- 无法通过 API 自动创建复杂数据模型的页面
- 必须手动在 UI 设计器中搭建页面
- 阻碍 AI 辅助 ERP 系统实施工作流

## 期望行为
- `apply-blueprint` 应能处理深层关联链而不栈溢出
- 要么限制递归深度,要么优化 fieldGroups 验证逻辑
- 提供有意义的错误信息,而非通用的栈溢出错误

## 补充说明
- 问题在 NocoBase 2.2.2 版本中仍然存在

你好 ,为定位具体递归路径,请补充可复现的 apply-blueprint 完整请求体(敏感数据可脱敏)、相关集合及 belongsTo 字段结构,以及报错时的完整服务端日志和堆栈。

NocoBase apply-blueprint 栈溢出问题补充材料

1. 完整的 apply-blueprint 请求体(可直接复现)

{
  "version": "1",
  "mode": "create",
  "navigation": {
    "group": { "title": "测试成本页面", "icon": "AppstoreOutlined" },
    "item": { "title": "测试六步成本核算单", "icon": "InboxOutlined" }
  },
  "page": { "title": "测试六步成本核算单" },
  "tabs": [
    {
      "key": "main",
      "title": "主表",
      "blocks": [
        {
          "key": "mainTable",
          "type": "table",
          "collection": "costCalculationSheets",
          "fields": ["sheetNo", "date", "quotationNo", "pricingMode", "status"],
          "actions": ["filter", "refresh"],
          "recordActions": ["view", "edit"]
        }
      ]
    }
  ],
  "defaults": {
    "collections": {
      "costCalculationSheets": {
        "fieldGroups": [
          { "key": "basic", "title": "基础信息", "fields": ["sheetNo", "date", "quotationNo"] },
          { "key": "rates", "title": "系数", "fields": ["deptMateRate", "deptWorkRate", "outRate", "custRate", "salaryRate"] },
          { "key": "pricing", "title": "定价", "fields": ["pricingMode", "pricingModeInferred"] },
          { "key": "status", "title": "状态", "fields": ["status", "sourceType"] },
          { "key": "time", "title": "时间", "fields": ["createdAt", "updatedAt"] }
        ]
      }
    }
  }
}

2. 相关集合及 belongsTo 字段结构

2.1 costCalculationSheets(六步成本核算单)

belongsTo 字段:

  • createdByusers (FK: createdById)
  • updatedByusers (FK: updatedById)
  • quotations_idquotations (FK: quotationsIdId)

2.2 quotations(报价单)

belongsTo 字段 (10个):

  • customers_idcustomers
  • currencies_idcurrencies
  • paymentTerms_idpaymentTerms
  • shipTypes_idshipTypes
  • employees_idemployees
  • endCustomers_idendCustomers
  • costSheets_idcostSheets
  • silverPrices_idsilverPrices
  • createdByusers
  • updatedByusers

2.3 customers(客户)

belongsTo 字段 (6个):

  • customerTypes_idcustomerTypes
  • currencies_idcurrencies
  • paymentTerms_idpaymentTerms
  • shipTypes_idshipTypes
  • createdByusers
  • updatedByusers

2.4 products(产品)

belongsTo 字段 (21个):

  • 包含 customers_id, employees_id, departments_id, productCategories_id 等多个关联

2.5 关联链深度示例

costCalculationSheets 
  → quotations (多个belongsTo)
    → customers (多个belongsTo)
      → customerTypes, currencies, paymentTerms, shipTypes
    → employees (多个belongsTo)
      → departments
    → costSheets (多个belongsTo)
      → products (多个belongsTo)
        → ... (继续递归)

3. 服务端日志和错误信息

3.1 CLI 错误输出

$ nb api flow-surfaces apply-blueprint --body-file test_blueprint.json -j
[31mRequest failed with status 500
{
  "errors": [
    {
      "message": "Maximum call stack size exceeded",
      "type": "internal_error",
      "code": "FLOW_SURFACE_INTERNAL_ERROR",
      "status": 500
    }
  ]
}

Diagnostic log: [日志文件路径已脱敏]

3.2 服务端日志文件内容

Request failed with status 500
{
  "errors": [
    {
      "message": "Maximum call stack size exceeded",
      "type": "internal_error",
      "code": "FLOW_SURFACE_INTERNAL_ERROR",
      "status": 500
    }
  ]
}

3.3 环境信息

  • NocoBase 版本: 2.2.2 (from package.json: "@nocobase/app": "2.2.2")
  • CLI 版本: 2.1.31
  • Node.js: v22.23.1
  • 操作系统: Linux
  • 数据库: PostgreSQL

4. 复现步骤

  1. 确保数据库中存在 costCalculationSheetsquotations 集合,且 quotations 有多个 belongsTo 字段
  2. 将上面的请求体保存为 test_blueprint.json
  3. 执行命令: nb api flow-surfaces apply-blueprint --body-file test_blueprint.json -j
  4. 观察错误: “Maximum call stack size exceeded”

5. 问题分析

5.1 根本原因

apply-blueprint 处理 fieldGroups 时,会递归检查所有 belongsTo 目标表的 fieldGroups。由于关联链过深(costCalculationSheets → quotations → customers → products 等),导致无限递归栈溢出。

5.2 触发条件

  • 集合有 belongsTo 关联链(深度 > 3层)
  • defaults.collections 中为该集合提供 fieldGroups
  • 关联的目标集合也有自己的 belongsTo 关联

5.3 临时解决方案

  • 手动在 UI 设计器中搭建页面(不使用 API)
  • 或者不提供 fieldGroups(但会导致验证错误)

6. 期望行为

  1. apply-blueprint 应能处理深层 belongsTo 关联链而不栈溢出
  2. 要么限制递归深度,要么优化 fieldGroups 验证逻辑
  3. 提供有意义的错误信息,而非通用的栈溢出错误
  4. 考虑添加递归深度限制或循环引用检测