nocobase/nocobase · error · Error

flowModels:attach position target is not a sibling under the

Error message

flowModels:attach position target is not a sibling under the same parent/subKey

What it means

Thrown by FlowModelRepository.attach when the before/after anchor target does not exist as a depth-1 child of the given parentId with the same subKey (type). The anchor must be an existing sibling in the exact same parent/subKey bucket; the SQL existence check returned no rows.

Source

Thrown at packages/plugins/@nocobase/plugin-flow-engine/src/server/repository.ts:1980

                            ON NodeInfo.descendant = TreeTable.descendant
                                AND NodeInfo.depth = 0
         WHERE TreeTable.depth = 1
           AND TreeTable.ancestor = :ancestor
           AND TreeTable.descendant = :descendant
           AND NodeInfo.type = :type
         LIMIT 1`,
        {
          type: 'SELECT',
          replacements: {
            ancestor: parentId,
            descendant: target,
            type: subKey,
          },
          transaction,
        },
      );
      if (!ok?.length) {
        throw new Error('flowModels:attach position target is not a sibling under the same parent/subKey');
      }
    }

    // 清理旧路径缓存(旧祖先)
    await this.clearXUidPathCache(modelUid, transaction);

    // 更新 root options:确保 nodesToModel 能按 subKey/subType 正确挂载
    await modelInstance.update(
      {
        options: {
          ...lodash.omit(modelInstance.get('options') as any, ['uid']),
          parentId,
          parent: parentId,
          subKey,
          subType,
        },
      },
      { transaction, hooks: false },

View on GitHub (pinned to fa42722fef)

Solutions

  1. Re-fetch the current children of parentId for the given subKey and use one of their uids as target.
  2. Verify the target is attached under the same parentId AND same subKey before anchoring.
  3. Fall back to position 'last' when no valid sibling anchor is available.

Example fix

// before
await repo.attach({ uid, parentId, subKey, subType: 'array', position: { type: 'after', target: staleUid } });
// after
const siblings = await repo.findChildren(parentId, subKey);
const position = siblings.some((s) => s.uid === targetUid)
  ? { type: 'after', target: targetUid }
  : 'last';
await repo.attach({ uid, parentId, subKey, subType: 'array', position });
Defensive patterns

Strategy: validation

Validate before calling

const siblings = await repo.findChildren(parentId, subKey);
const anchorOk = typeof position === 'object' && siblings.some((s) => s.uid === position.target);
await repo.attach({ uid, parentId, subKey, subType, position: anchorOk ? position : 'last' });

Type guard

const isExistingSibling = (siblings: { uid: string }[], target: string) =>
  siblings.some((s) => s.uid === String(target).trim());

Try / catch

try {
  await repo.attach(opts);
} catch (e) {
  if (String(e.message).includes('not a sibling under the same parent/subKey')) {
    await refreshSiblings();
    await repo.attach({ ...opts, position: 'last' });
  } else throw e;
}

Prevention

When it happens

Trigger: Calling flowModels.attach with position { type:'before'|'after', target } where the target uid is: not yet attached, attached under a different parent, attached under the same parent but a different subKey, or simply misspelled/deleted.

Common situations: Anchoring against a node that was just deleted in another tab; anchoring against a cousin node (same grandparent, different parent); race between fetching sibling list and attaching; uid typo after copy-paste.

Related errors


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