Crosstalk-Solutions/project-nomad · error · Error

sysbench disk-write benchmark produced no parseable MiB/s —

Error message

sysbench disk-write benchmark produced no parseable MiB/s — aborting

What it means

Thrown by BenchmarkService after running a sysbench disk-write benchmark inside a container when the regex parsing of sysbench's stdout fails to extract a positive, finite MiB/s value. The code deliberately fails loudly (throwing instead of returning 0) because MiB/s is the primary scored metric, so a silent zero would corrupt benchmark scoring.

Source

Thrown at admin/app/services/benchmark_service.ts:1556

    // --file-extra-flags=direct (O_DIRECT) on the run bypasses the page cache (W4).
    const output = await this._runSysbenchCommand([
      'sh',
      '-c',
      'sysbench fileio --file-total-size=1G --file-num=4 prepare && ' +
        'sysbench fileio --file-total-size=1G --file-num=4 --file-test-mode=seqwr --file-extra-flags=direct --time=30 run && ' +
        'sysbench fileio --file-total-size=1G --file-num=4 cleanup',
    ])

    // Parse output - look for the Throughput section
    const writeMatch = output.match(/written,\s*MiB\/s:\s*([\d.]+)/i)
    const writesPerSecMatch = output.match(/writes\/s:\s*([\d.]+)/i)

    logger.debug(`[BenchmarkService] Disk write output parsing - written: ${writeMatch?.[1]}, writes/s: ${writesPerSecMatch?.[1]}`)

    // Scored primary metric: fail loudly instead of silently scoring zero on a parse miss
    const writeMbPerSec = writeMatch ? parseFloat(writeMatch[1]) : Number.NaN
    if (!writeMatch || !Number.isFinite(writeMbPerSec) || writeMbPerSec <= 0) {
      throw new Error('sysbench disk-write benchmark produced no parseable MiB/s — aborting')
    }

    return {
      reads_per_second: 0,
      writes_per_second: writesPerSecMatch ? parseFloat(writesPerSecMatch[1]) : 0,
      read_mb_per_sec: 0,
      write_mb_per_sec: writeMbPerSec,
      total_time: 30,
    }
  }

  /**
   * Run a sysbench command in a Docker container
   */
  private async _runSysbenchCommand(cmd: string[]): Promise<string> {
    let container: Dockerode.Container | null = null
    try {
      // Create container with TTY to avoid multiplexed output

View on GitHub (pinned to 0bd1c6f4f9)

Solutions

  1. Inspect the captured sysbench stdout (add a logger.debug of the raw output) and compare it against the writeMatch regex; adjust the regex to the actual format
  2. Pin the sysbench/toolbox container image and version so output format is stable
  3. Set LC_ALL=C (or an English locale) in the container env so number formatting is deterministic
  4. Guard upstream: verify the sysbench command exits with code 0 before parsing, and treat non-zero exits as a distinct error
  5. If a '0 MiB/s' result is legitimately possible in your environment, decide on an explicit floor value instead of relying on the parser to reject it

Example fix

// before
const writeMbPerSec = writeMatch ? parseFloat(writeMatch[1]) : Number.NaN
if (!writeMatch || !Number.isFinite(writeMbPerSec) || writeMbPerSec <= 0) {
  throw new Error('sysbench disk-write benchmark produced no parseable MiB/s — aborting')
}

// after
const writeMbPerSec = writeMatch ? Number.parseFloat(writeMatch[1].replace(',', '.')) : Number.NaN
if (!writeMatch || !Number.isFinite(writeMbPerSec) || writeMbPerSec <= 0) {
  logger.error(`[BenchmarkService] Unparseable sysbench output:\n${rawOutput}`)
  throw new Error('sysbench disk-write benchmark produced no parseable MiB/s — aborting')
}
Defensive patterns

Strategy: validation

Validate before calling

const m = /([\d.]+)\s*MiB\/s/.exec(stdout)
if (!m || !Number.isFinite(parseFloat(m[1].replace(',', '.'))) || parseFloat(m[1]) <= 0) {
  throw new Error('Skip benchmark: sysbench output format unrecognized')
}

Type guard

function hasValidWriteMiBs(stdout: string): boolean {
  const m = /([\d.]+)\s*MiB\/s/.exec(stdout)
  return !!m && Number.isFinite(Number.parseFloat(m[1].replace(',', '.'))) && Number(m[1]) > 0
}

Try / catch

try { runDiskWriteBenchmark() } catch (e) { if (e instanceof Error && e.message.includes('no parseable MiB/s')) { /* surface parse failure, keep prior stages' results */ } else throw e }

Prevention

When it happens

Trigger: Running the disk-write benchmark stage where sysbench output format differs from the expected 'MiB/s' regex (e.g. sysbench version differences, locale-adjusted decimal separators, output polluted by container logs/warnings), sysbench exiting before printing results, or parseFloat yielding NaN/0 because the matched group was malformed.

Common situations: Upgrading sysbench or the Docker image so output lines change (e.g. 'transferred (X MiB/s)' wording changes), non-English locale printing commas as decimal separators, OOM/killed container producing truncated output, or a changed block-size/files flag causing sysbench to print a different summary layout.

Related errors


AI-assisted analysis of Crosstalk-Solutions/project-nomad@0bd1c6f4f9 (2026-08-27). Data as JSON: /api/errors/4b986b8078583cfa. Report an issue: GitHub.