jackwener/OpenCLI · error · CommandExecutionError
Bilibili relation modify did not verify ${expectedLabel}; la
Error message
Bilibili relation modify did not verify ${expectedLabel}; last attribute=${lastAttribute} What it means
waitForRelation polls Bilibili's relation API (attribute = your relationship flag with a user, e.g. follow/block states) after a follow/unfollow/block mutation, applying a predicate with a 5s deadline. If the relation attribute never satisfies the predicate within the timeout window (polling every 500ms), it throws CommandExecutionError with the last observed attribute so you can see what state the API actually reports. This means the modify command ran, but the change was not (yet) reflected server-side.
Source
Thrown at clis/bilibili/relation.js:41
const payload = await fetchJson(page, `https://api.bilibili.com/x/relation?fid=${mid}`);
requireOkPayload(payload, 'relation query');
const attribute = payload?.data?.attribute;
if (typeof attribute !== 'number') {
throw new CommandExecutionError('Bilibili relation query returned a malformed attribute');
}
return attribute;
}
export async function waitForRelation(page, mid, predicate, expectedLabel) {
const deadline = Date.now() + RELATION_VERIFY_TIMEOUT_MS;
let lastAttribute;
while (Date.now() <= deadline) {
lastAttribute = await fetchRelationAttribute(page, mid);
if (predicate(lastAttribute)) return lastAttribute;
if (typeof page.wait !== 'function') break;
await page.wait({ time: RELATION_VERIFY_POLL_MS / 1000 });
}
throw new CommandExecutionError(
`Bilibili relation modify did not verify ${expectedLabel}; last attribute=${lastAttribute}`,
);
}
View on GitHub (pinned to 49907e53dc)
Solutions
- Retry the command after a few seconds — often the attribute eventually flips; server lag is the most common cause
- Check the lastAttribute value in the message against Bilibili's relation attribute enum to see what state you are actually in (e.g. already-followed vs not-followed)
- Verify the mid is correct and the account is not risk-controlled/limited (try the same action manually in a browser)
- Ensure the automation environment provides a real browser page with a wait() method so all polls within the 5s window run
- If operations legitimately take longer, increase RELATION_VERIFY_TIMEOUT_MS or wrap the command in an application-level retry with backoff
Example fix
// before
await waitForRelation(page, mid, (a) => a === 2, 'followed');
// after
for (let attempt = 1; attempt <= 3; attempt++) {
try { await waitForRelation(page, mid, (a) => a === 2, 'followed'); break; }
catch (e) { if (attempt === 3) throw e; await new Promise(r => setTimeout(r, 2000)); }
} Defensive patterns
Strategy: retry
Validate before calling
const attr = await fetchRelationAttribute(page, mid);
if (!predicate(attr)) console.warn('relation not yet in expected state:', attr); Try / catch
try {
await waitForRelation(page, mid, (a) => a === 2, 'followed');
} catch (e) {
if (String(e.message).includes('did not verify')) {
// inspect lastAttribute, back off and retry the whole modify+verify cycle
} else throw e;
} Prevention
- Wrap relation mutations in an application-level retry with exponential backoff
- Always run against a page object that implements wait() so full polling happens
- Log the lastAttribute and compare against Bilibili's relation attribute enum before retrying
- Avoid rapid successive follow/unfollow cycles that trip risk control
When it happens
Trigger: Calling a bilibili relation command (follow/unfollow/block) and then the relation API keeps returning an attribute that fails the predicate for 5+ seconds; also triggered when page.wait is not a function — the loop breaks after a single poll and throws immediately even though the server may just need more time.
Common situations: Bilibili server-side lag/replication delay after a follow; the mutation silently failed (invalid mid, risk-control shadow rejection, need 2FA for some operations); an already-followed user being unfollowed but attribute mapping differs; running in an environment where the page object lacks wait() so only one poll happens.
Related errors
- Bilibili creator comparison
- Timeout waiting for Antigravity reply after ${timeout / 1000
- FETCH_ERROR
- archive wayback request failed: ${error?.message || error}
- Bilibili creator comparison API returned a malformed envelop
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/a91eaf5b49259f27.
Report an issue: GitHub.