jackwener/OpenCLI · error · CommandExecutionError

抖音作品 ${awemeId} 删除后仍在作品列表中,删除未确认

Error message

抖音作品 ${awemeId} 删除后仍在作品列表中,删除未确认

What it means

Thrown after POSTing the aweme/delete API: the library polls the work list for up to 10 seconds (500ms intervals) and throws if the aweme_id still appears, meaning the delete was not confirmed. Douyin deletion can be asynchronous; the library refuses to report success without confirmation.

Source

Thrown at clis/douyin/delete.js:150

                throw fallbackError;
            }
        }

        const before = await findWorkListItem(page, awemeId);
        if (!before) {
            throw new CommandExecutionError(`抖音作品 ${awemeId} 未在作品列表中找到,未执行删除`);
        }
        const url = 'https://creator.douyin.com/web/api/media/aweme/delete/?aid=1128';
        await browserFetch(page, 'POST', url, { body: { aweme_id: awemeId }, timeoutMs: 8000 });
        const deadline = Date.now() + 10_000;
        while (Date.now() < deadline) {
            await sleep(500);
            const after = await findWorkListItem(page, awemeId);
            if (!after) {
                return [{ status: `✅ 已删除 ${awemeId}` }];
            }
        }
        throw new CommandExecutionError(`抖音作品 ${awemeId} 删除后仍在作品列表中,删除未确认`);
    },
});

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Increase the polling deadline beyond 10s and retry — propagation can be slow
  2. Re-run the delete; if it persists, delete manually from creator-micro to confirm the work's state
  3. Check the delete API response body for error fields instead of assuming 200 means accepted
  4. Re-login if risk-control or partial session is suspected

Example fix

// before
const deadline = Date.now() + 10_000;
// after: longer window with exponential backoff
let deadline = Date.now() + 60_000;
while (Date.now() < deadline) { await sleep(2000); if (!await findWorkListItem(page, awemeId)) return ok; }
throw new CommandExecutionError(`delete unconfirmed for ${awemeId}`);
Defensive patterns

Strategy: retry

Validate before calling

// confirm the delete POST itself reported success before relying on polling
const delRes = await browserFetch(page, 'POST', deleteUrl, { body: { aweme_id: id } });
if (delRes?.error) throw new Error('delete API rejected: ' + JSON.stringify(delRes));

Type guard

function isGoneFromList(list, awemeId) {
  return Array.isArray(list) && !list.some(e => String(e.aweme_id ?? e.item_id ?? '') === String(awemeId));
}

Try / catch

try {
  await deleteCommand(page, awemeId);
} catch (e) {
  if (/删除后仍在作品列表中/.test(e.message)) {
    await sleep(30000); // allow server-side propagation
    const still = await findWorkListItem(page, awemeId);
    if (!still) return 'deleted (confirmed late)';
  } throw e;
}

Prevention

When it happens

Trigger: The delete API returned 200 but deletion is pending/asynchronous server-side; the delete actually failed silently (risk-control or permission issue); the work list cache still serves the item; findWorkListItem keeps matching due to stale list data.

Common situations: Deleting large videos whose removal takes >10s to propagate; account under risk-control where delete API calls are silently dropped; cookie/session partially valid so the POST is ignored.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/d48a43572339f57b. Report an issue: GitHub.