jackwener/OpenCLI · error · ArgumentError

Argument "${argDef.name}" must be a boolean (true/false). Re

Error message

Argument "${argDef.name}" must be a boolean (true/false). Received: "${val}"

What it means

For arguments typed 'boolean'/'bool', coerceAndValidateArgs accepts true/false (case-insensitive) and '1'/'0' strings; numeric/other types are coerced with Boolean(). A string that is not one of true/false/1/0 (case-insensitive) throws ArgumentError requiring a boolean value.

Source

Thrown at src/execution.ts:82

      );
    }

    if (val !== undefined && val !== null) {
      if (argDef.type === 'int' || argDef.type === 'number') {
        const num = Number(val);
        if (!Number.isFinite(num)) {
          throw new ArgumentError(`Argument "${argDef.name}" must be a valid number. Received: "${val}"`);
        }
        if (argDef.type === 'int' && !Number.isInteger(num)) {
          throw new ArgumentError(`Argument "${argDef.name}" must be a valid integer. Received: "${val}"`);
        }
        result[argDef.name] = num;
      } else if (argDef.type === 'boolean' || argDef.type === 'bool') {
        if (typeof val === 'string') {
          const lower = val.toLowerCase();
          if (lower === 'true' || lower === '1') result[argDef.name] = true;
          else if (lower === 'false' || lower === '0') result[argDef.name] = false;
          else throw new ArgumentError(`Argument "${argDef.name}" must be a boolean (true/false). Received: "${val}"`);
        } else {
          result[argDef.name] = Boolean(val);
        }
      }

      const coercedVal = result[argDef.name];
      if (argDef.choices && argDef.choices.length > 0) {
        if (!argDef.choices.map(String).includes(String(coercedVal))) {
          throw new ArgumentError(`Argument "${argDef.name}" must be one of: ${argDef.choices.join(', ')}. Received: "${coercedVal}"`);
        }
      }
    } else if (argDef.default !== undefined) {
      result[argDef.name] = argDef.default;
    }
  }
  return result;
}

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Use true/false (or 1/0), e.g. --headless true.
  2. Map yes/no or on/off to true/false in the calling script before passing.
  3. In programmatic use, pass actual booleans rather than strings.
  4. Check the argument's declared type; if it should accept more forms, update the arg definition (library-side).

Example fix

// before
opencli run --headless yes
// after
opencli run --headless true
Defensive patterns

Strategy: validation

Validate before calling

function toBool(v: unknown): boolean {
  if (typeof v === 'boolean') return v;
  const s = String(v).toLowerCase();
  if (s === 'true' || s === '1') return true;
  if (s === 'false' || s === '0') return false;
  throw new Error(`Expected boolean (true/false/1/0), got: ${String(v)}`);
}
kwargs.headless = toBool(kwargs.headless);

Type guard

const isBooleanLike = (v: unknown): v is boolean | 'true' | 'false' | '1' | '0' =>
  typeof v === 'boolean' || ['true', 'false', '1', '0'].includes(String(v).toLowerCase());

Try / catch

try {
  await opencli.run(cmd, kwargs);
} catch (e) {
  if (/must be a boolean/.test(e.message)) {
    console.error(`${e.message} — map yes/no or on/off to true/false first.`);
  } else throw e;
}

Prevention

When it happens

Trigger: Passing --headless yes, --debug on, --enabled TRUE-ish variants outside the accepted set (e.g. 'y', 't'), or kwargs like { dryRun: 'maybe' } to a bool-typed argument.

Common situations: Shell conventions using yes/no or on/off; interactive prompts feeding 'Y'/'N'; config files with boolean-like strings other than the accepted four.

Related errors


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