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
- Set an integer from 1 through 8, or omit the field entirely (default 2).
- When sourcing from env or flags, parse and clamp: Math.min(8, Math.max(1, Math.trunc(Number(value)))), and reject NaN.
- 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
- Source the value from the schema-validated cordis.yml Config, never raw env strings.
- Keep the 1-8 bound in generated config docs and examples.
- Treat a startup throw here as intended fail-loud behavior — do not catch-and-default.
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
- client-connection: trustedHosts entry ${JSON.stringify(entry
- client-connection maxRequestBodyBytes (${String(maxRequestBo
- permission settings has no defaultPreset value
- dsh-code-runtime-worker-thread: config.${key} must be a posi
- dsh-code-runtime-worker-thread: config.maxOutputBytes must b
AI-assisted analysis of deepseek-ai/deepseek-harness@b150a551b8 (2026-08-24).
Data as JSON: /api/errors/229b69813e261436.
Report an issue: GitHub.