deepseek-ai/deepseek-harness · error · Error

attachment-local: imageCompressionConcurrency must be an int

Error message

attachment-local: imageCompressionConcurrency must be an integer from 1 through ${MAX_IMAGE_COMPRESSION_CONCURRENCY}

What it means

LocalAttachmentStore's constructor validates imageCompressionConcurrency — the number of simultaneous native sharp transformations per store — and throws a plain Error when the value is not a safe integer in [1, 8] (MAX_IMAGE_COMPRESSION_CONCURRENCY; default 2). The schemastery Config enforces the same range for cordis.yml loads, so this throw chiefly guards direct or programmatic construction with values like 0, 9, 2.5, or NaN, failing at plugin-load time before any image operation.

Source

Thrown at packages/attachment/attachment-local/src/index.ts:177

    super(ctx)
    this.root = resolve(join(resolveDshHome(config.dshHome), 'attachments', 'v1'))
    this.imageLimits = Object.freeze({
      maxImageBytes: config.maxImageBytes ?? DEFAULT_MAX_IMAGE_BYTES,
      maxImagesPerMessage: config.maxImagesPerMessage ?? DEFAULT_MAX_IMAGES_PER_MESSAGE,
      maxMessageImageBytes: config.maxMessageImageBytes ?? DEFAULT_MAX_MESSAGE_IMAGE_BYTES,
      maxImagePixels: config.maxImagePixels ?? DEFAULT_MAX_IMAGE_PIXELS,
      maxImageDimension: config.maxImageDimension ?? DEFAULT_MAX_IMAGE_DIMENSION,
      mediaTypes: Object.freeze(['image/png', 'image/jpeg', 'image/webp', 'image/gif'] as const),
    })
    this.normalizationPolicy = Object.freeze({
      maxDimension: config.normalizedImageMaxDimension ?? DEFAULT_NORMALIZED_IMAGE_MAX_DIMENSION,
      maxBytes: config.normalizedImageMaxBytes ?? DEFAULT_NORMALIZED_IMAGE_MAX_BYTES,
    })
    const compressionConcurrency = config.imageCompressionConcurrency ?? DEFAULT_IMAGE_COMPRESSION_CONCURRENCY
    if (!Number.isSafeInteger(compressionConcurrency)
      || compressionConcurrency < 1
      || compressionConcurrency > MAX_IMAGE_COMPRESSION_CONCURRENCY) {
      throw new Error(
        `attachment-local: imageCompressionConcurrency must be an integer from 1 through ${MAX_IMAGE_COMPRESSION_CONCURRENCY}`,
      )
    }
    this.imageCompressionConcurrency = compressionConcurrency
    this.compression = new CompressionLimiter(compressionConcurrency)
  }

  async validateImage(input: SaveImageAttachment): Promise<void> {
    await this.compression.run(() => validateImageFile(input, this.imageLimits, this.normalizationPolicy))
  }

  override async saveImages(inputs: readonly SaveImageAttachment[]): Promise<readonly ImageAttachmentRef[]> {
    this.validateImageBatch(inputs)
    const prepared = await Promise.all(inputs.map(input => this.compression.run(
      () => prepareImageFile(input, this.imageLimits, this.normalizationPolicy),
    )))
    const refs: ImageAttachmentRef[] = []
    for (const image of prepared) refs.push(await commitPreparedImageFile(this.root, image))

View on GitHub (pinned to b150a551b8)

Solutions

  1. Set an integer from 1 through 8, or omit the field entirely (default 2).
  2. When sourcing from env or flags, parse and clamp: Math.min(8, Math.max(1, Math.trunc(Number(value)))), and reject NaN.
  3. If you need more than 8 concurrent native transformations, scale out with additional store instances rather than exceeding the cap.

Example fix

// before
ctx.plugin(LocalAttachmentStore, { dshHome, imageCompressionConcurrency: 16 })

// after
ctx.plugin(LocalAttachmentStore, { dshHome, imageCompressionConcurrency: 8 })
Defensive patterns

Strategy: validation

Validate before calling

const raw = Number(process.env.IMAGE_COMPRESSION_CONCURRENCY ?? '2')
if (!Number.isSafeInteger(raw) || raw < 1 || raw > 8) {
  throw new Error('IMAGE_COMPRESSION_CONCURRENCY must be an integer from 1 through 8')
}

Try / catch

try {
  ctx.plugin(LocalAttachmentStore, config)
} catch (error) {
  if (error instanceof Error && error.message.startsWith('attachment-local: imageCompressionConcurrency')) {
    // configuration error: fail startup with the config path in the message
  }
  throw error
}

Prevention

When it happens

Trigger: Constructing or loading LocalAttachmentStore with config.imageCompressionConcurrency outside 1-8: 0 to disable, 9+ for more parallelism, fractional values, or NaN/Infinity from unvalidated env-derived input passed around the schema.

Common situations: Performance tuning that copies a larger worker count into this field; sourcing the value from an env var without parsing or clamping; test harnesses constructing the store directly with hand-built config objects.

Understand the failure class

Background: Config validation failed: what "invalid value for {key}" and settings-rejection errors mean across 19 open-source libraries — this error's family across 19 libraries.

Related errors


AI-assisted analysis of deepseek-ai/deepseek-harness@b150a551b8 (2026-08-24). Data as JSON: /api/errors/229b69813e261436. Report an issue: GitHub.