Share Notes

chundev

View the Project on GitHub latteouka/share-notes

XSOAR setList 版本衝突除錯紀錄

日期:2026-03-16 環境:Cortex XSOAR 測試環境


TL;DR

在 XSOAR Playbook 中使用 createList + setList 更新 List 時,會遇到 DB Version 'X' and Insert version 'Y' do not match 版本衝突錯誤。根本原因是 XSOAR 的樂觀鎖機制(Optimistic Locking),Playbook 執行過程中快取的版本號已過期。最終解法是寫一個自訂 Automation Script,在 setList 前先 getList 刷新版本號。


背景

開發一個 DRIP 設備清單同步 Playbook,流程為:

  1. 呼叫 DRIP API(GetIPMACList)取得 3 個 Tracker 的設備資料
  2. 精簡欄位(只保留 IP、Hostname、系統功能、系統分級、Tracker)
  3. 合併 3 份資料
  4. 寫入 XSOAR List 供其他 Playbook 查詢

錯誤訊息

在「寫入 List」步驟持續出現:

failed to update list [DRIP_設備清單] in database:
DB Version '7' and Insert version '6' do not match
for id: DRIP_設備清單 on bucket [] [dataListsBucket]

除錯過程

❌ 嘗試 1:移除 createList,只用 setList

假設: createList 每次重建 List 改變了版本號,導致後續 setList 版本不匹配。

結果: 移除 createList 後,問題依然存在。版本衝突不是 createList 造成的。

❌ 嘗試 2:加回 createList + errorPath

做法: createList 設定 continueonerrortype: errorPath,List 已存在時走 error path 繼續。

結果: 同樣的版本衝突錯誤。setList 快取的版本號在 Playbook 長時間執行後已過期。

❌ 嘗試 3:先 deleteList 再 createList

做法: 在寫入前先刪除舊 List,再用 createList 全新建立。

問題 1: deleteList 不是 XSOAR 內建指令,需要 Core REST API integration。

問題 2: 如果在 Playbook 開頭就刪除,API 全部失敗時 List 會完全不可用。如果移到 Merge 之後才刪除,仍然需要 Core REST API。

結果: 此路不通。

✅ 最終解法:自訂 Script — getList 刷新 + setList 寫入

關鍵發現: 版本衝突是因為 Playbook 執行過程中(呼叫 3 次 API + 精簡 + 合併),XSOAR 快取的 List 版本號已經與 DB 不一致。在 Automation Script 內部先 getList 可以刷新版本號到最新,緊接著 setList 就能成功。

# SetListWithRetry automation script 核心邏輯
import time

def main():
    list_name = demisto.args().get('listName', '')
    list_data = demisto.args().get('listData', '')
    max_retries = 5
    retry_delay = 2

    for attempt in range(max_retries):
        # 關鍵:每次重試前先 getList 刷新版本號
        demisto.executeCommand('getList', {'listName': list_name})

        # 馬上 setList,此時版本號是最新的
        result = demisto.executeCommand('setList', {
            'listName': list_name,
            'listData': list_data
        })

        if not isError(result[0]):
            # 成功
            return

        error_msg = result[0].get('Contents', '')
        if 'do not match' in str(error_msg):
            time.sleep(retry_delay)
            continue
        else:
            return_error(f'setList 失敗: {error_msg}')
            return

    return_error(f'重試 {max_retries} 次後仍失敗')

main()

XSOAR List 相關指令整理

指令 用途 備註
createList 建立新 List List 已存在會報錯
getList 讀取 List 內容 同時刷新版本號快取
setList 覆寫 List 內容 有樂觀鎖,版本不匹配會失敗
addToList 新增資料到 List
deleteList ❌ 不存在 需透過 Core REST API

關鍵學到的事

  1. XSOAR 的 setList 有樂觀鎖機制 — 不是單純的覆寫,會檢查版本號
  2. Playbook 執行時間越長,版本衝突機率越高 — 版本號在 Playbook 開始時快取,執行過程中可能過期
  3. 在 Script 內 getList + setList 背靠背執行可以解決 — 讀寫在同一個 Script 內完成,版本號來不及過期
  4. deleteList 不是內建指令 — 要刪除 List 需要 Core REST API integration(core-api-post uri="/lists/delete"
  5. 不要在 Playbook 開頭刪除資料 — 如果後續步驟失敗,舊資料也沒了

最終 Playbook 架構

開始
  → API Tracker 1 → 精簡欄位
  → API Tracker 2 → 精簡欄位
  → API Tracker 3 → 精簡欄位
  → 合併 3 份結果
  → SetListWithRetry (getList 刷新 + setList 寫入)
  → 回填資訊 → 結案