jackwener/OpenCLI · error · CommandExecutionError

Bilibili creator comparison omitted metric ${definition.key}

Error message

Bilibili creator comparison omitted metric ${definition.key}

What it means

metricValue checks that the metric key defined in the METRICS whitelist (e.g. `play`, `full_play_ratio`) actually exists on the source object (the row itself for target-sourced metrics like `duration`, otherwise `target.stat`). If the key is missing entirely, the library throws instead of silently emitting a wrong/empty value. null values are allowed and pass through, only total absence throws.

Source

Thrown at clis/bilibili/creator-stats.js:120

        throw new CommandExecutionError(`Bilibili creator comparison returned duplicate rows for ${bvid}`);
    }
    if (matches.length === 0) {
        throw new EmptyResultError(
            `bilibili creator-stats ${bvid}`,
            'The manuscript was not present in the latest 100 creator analytics rows; it may be older, not owned by this account, or not analyzed yet.',
        );
    }
    const target = matches[0];
    if (!isRecord(target.stat)) {
        throw new CommandExecutionError(`Bilibili creator comparison returned malformed stat data for ${bvid}`);
    }
    return target;
}

function metricValue(target, definition) {
    const source = definition.source === 'target' ? target : target.stat;
    if (!Object.prototype.hasOwnProperty.call(source, definition.key)) {
        throw new CommandExecutionError(`Bilibili creator comparison omitted metric ${definition.key}`);
    }
    const raw = source[definition.key];
    if (raw === null) return null;
    if (typeof raw !== 'number' || !Number.isFinite(raw) || raw < 0) {
        throw new CommandExecutionError(`Bilibili creator comparison returned malformed metric ${definition.key}`);
    }
    if (definition.unit === 'percent' && raw > 10_000) {
        throw new CommandExecutionError(`Bilibili creator comparison returned out-of-range percentage ${definition.key}`);
    }
    if ((definition.unit === 'count' || definition.unit === 'seconds') && !Number.isSafeInteger(raw)) {
        throw new CommandExecutionError(`Bilibili creator comparison returned non-integer metric ${definition.key}`);
    }
    return definition.divisor ? raw / definition.divisor : raw;
}

cli({
    site: 'bilibili',
    name: 'creator-stats',

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Wait and retry — newly analyzed manuscripts often gain fields once analytics are computed.
  2. Verify the actual response body of the compare endpoint and update the METRICS key mapping in creator-stats.js if Bilibili renamed the field.
  3. Try a different, older manuscript to confirm the endpoint still returns all metrics.
  4. Update the CLI to a version whose METRICS whitelist matches the current Bilibili API.

Example fix

// before (throws on missing key)
const v = metricValue(target, def);
// after (caller tolerates omission)
const source = def.source === 'target' ? target : target.stat;
const v = Object.prototype.hasOwnProperty.call(source, def.key) ? metricValue(target, def) : null;
Defensive patterns

Strategy: validation

Validate before calling

const KEYS = ['play','like','comment','dm','fav','coin','share','total_new_attention_cnt','full_play_ratio','active_fans_rate','tm_rate','crash_rate','interact_rate','play_trans_fan_rate'];
const source = def.source === 'target' ? row : row.stat;
if (!KEYS.every((k) => Object.prototype.hasOwnProperty.call(source ?? {}, k))) { /* treat metrics as unavailable */ }

Type guard

function hasMetric(source, key) {
    return Boolean(source) && typeof source === 'object' && Object.prototype.hasOwnProperty.call(source, key);
}

Try / catch

try {
    const rows = await creatorStats(bvid);
} catch (e) {
    if (/omitted metric/.test(e.message)) {
        // degrade: render partial stats or nulls instead of aborting
    } else throw e;
}

Prevention

When it happens

Trigger: Bilibili's compare endpoint omits a whitelisted key from `target.stat` (or from the row for `durationSeconds`), e.g. after an API schema change or for archive types that don't carry certain counters.

Common situations: Undocumented API contract drift after Bilibili renames/removes fields; new archives where analytics fields haven't been populated yet; region-specific A/B rollouts of the creator center that drop fields.

Related errors


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