signalapp/Signal-Server · error · IllegalArgumentException

range-split-chunk-size-bytes must be positive

Error message

range-split-chunk-size-bytes must be positive

What it means

range-split-chunk-size-bytes controls the chunk size used to split the account range for parallel crawling; a zero or negative value is invalid, so crawlAccounts throws IllegalArgumentException before doing work.

Solutions

  1. Pass a positive byte value, e.g. --range-split-chunk-size-bytes 1000000
  2. Fix the variable/expression that supplied the flag value
  3. Check script ordering so the value is set before the command runs

Example fix

// before
--range-split-chunk-size-bytes 0
// after
--range-split-chunk-size-bytes 1000000
Defensive patterns

Strategy: validation

Validate before calling

long chunk = Long.parseLong(args["range-split-chunk-size-bytes"]);
if (chunk <= 0) throw new IllegalArgumentException("range-split-chunk-size-bytes must be positive");

Try / catch

try { crawlAccounts(accounts); } catch (IllegalArgumentException e) { System.err.println("config: " + e.getMessage()); System.exit(2); }

Prevention

When it happens

Trigger: Running the trim command with --range-split-chunk-size-bytes of 0 or a negative number.

Common situations: Placeholder value left in a runbook; a computed/default expression evaluating to 0; misunderstanding that the value is in bytes.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of signalapp/Signal-Server@100ab61c82 (2026-09-09). Data as JSON: /api/errors/accb5d3d1b9ea58e. Report an issue: GitHub.

Appendix: source

Thrown at service/src/main/java/org/whispersystems/textsecuregcm/workers/TrimOversizedFoundationDbMessageQueuesCommand.java:116

            """);
  }

  @Override
  protected void crawlAccounts(final Flux<Account> accounts) {
    final long maxQueueSizeBytes = getNamespace().getLong(MAX_QUEUE_SIZE_BYTES_ARGUMENT);
    final long targetQueueSizeBytes = getNamespace().getLong(TARGET_QUEUE_SIZE_BYTES_ARGUMENT);
    final long rangeSplitChunkSizeBytes = getNamespace().getLong(RANGE_SPLIT_CHUNK_SIZE_BYTES_ARGUMENT);

    if (targetQueueSizeBytes <= 0) {
      throw new IllegalArgumentException("target-queue-size-bytes must be positive");
    }

    if (targetQueueSizeBytes >= maxQueueSizeBytes) {
      throw new IllegalArgumentException("target-queue-size-bytes must be less than max-queue-size-bytes");
    }

    if (rangeSplitChunkSizeBytes <= 0) {
      throw new IllegalArgumentException("range-split-chunk-size-bytes must be positive");
    }

    final boolean dryRun = getNamespace().getBoolean(DRY_RUN_ARGUMENT);
    final int maxConcurrency = getNamespace().getInt(MAX_CONCURRENCY_ARGUMENT);

    final MessagesManager messagesManager = getCommandDependencies().messagesManager();

    accounts
        .flatMapIterable(account ->
            account.getDevices().stream().map(
                device -> new Pair<>(new AciServiceIdentifier(account.getAccountIdentifier()), device)).toList())
        .doOnNext(_ -> Metrics.counter(QUEUES_INSPECTED_COUNTER_NAME, "dryRun", String.valueOf(dryRun)).increment())
        .flatMap(accountAndDevice ->
            messagesManager.trimQueue(accountAndDevice.first(), accountAndDevice.second(), maxQueueSizeBytes, targetQueueSizeBytes, rangeSplitChunkSizeBytes, dryRun),
            maxConcurrency)
        .onErrorResume(e  -> {
          LOGGER.error("Failed to trim queue", e);
          return Mono.empty();

View on GitHub (pinned to 100ab61c82)