deepseek-ai/deepseek-harness · error · Error
attachment-local: imageCompressionConcurrency must be an…
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.
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: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- BasicCompactionConfig: auto must be a boolean
- BasicCompactionConfig: duplicate model policy for
- BasicCompactionConfig: modelPolicies must be an array
- BasicCompactionConfig
- client-connection maxRequestBodyBytes
AI-assisted analysis of deepseek-ai/deepseek-harness@b150a551b8 (2026-08-24).
Data as JSON: /api/errors/229b69813e261436.
Report an issue: GitHub.
Appendix: 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)