deepseek-ai/deepseek-harness · error

BasicCompactionConfig: modelPolicies must be an array

Error message

BasicCompactionConfig: modelPolicies must be an array

What it means

compaction-basic validates its whole plugin configuration eagerly at load time in resolveConfig(). modelPolicies holds exact provider/model override objects and must be an Array; resolveModelPolicies() rejects any other type before defaults are applied, so a malformed override table cannot silently match no policy.

Source

Thrown at packages/compaction/compaction-basic/src/config.ts:197

/** Reject a capacity-independent retention conflict at plugin load. */
function validateRatioRetention(
  thresholdRatio: number,
  retention: ResolvedRetention,
  name: string,
): void {
  if (retention.retainRatio !== undefined && retention.retainRatio >= thresholdRatio) {
    throw new Error(
      `${name}: retainRatio (${retention.retainRatio}) must be less than `
      + `the resolved thresholdRatio (${thresholdRatio})`,
    )
  }
}

/** Validate, detach, and reject duplicate exact-target policies. */
function resolveModelPolicies(configured: unknown): ModelCompactPolicyConfig[] {
  if (configured === undefined) return []
  if (!Array.isArray(configured)) {
    throw new Error('BasicCompactionConfig: modelPolicies must be an array')
  }
  const seen = new Set<string>()
  return configured.map((source: unknown, index) => {
    const name = `BasicCompactionConfig: modelPolicies[${index}]`
    assertModelPolicy(source, name)
    const key = `${source.provider}\u0000${source.model}`
    if (seen.has(key)) {
      throw new Error(
        `BasicCompactionConfig: duplicate model policy for ${source.provider}/${source.model}`,
      )
    }
    seen.add(key)
    return { ...source }
  })
}

/** Validate one untrusted exact-target override and narrow its public type. */
function assertModelPolicy(

View on GitHub (pinned to b150a551b8)

Solutions

  1. Rewrite modelPolicies as a YAML block list: each entry starts with '- ' and carries provider, model, and override fields
  2. If you keyed entries by provider (modelPolicies: { deepseek: { model: chat, ... } }), convert each group into list items that state both provider and model explicitly
  3. If no per-model overrides are needed, delete the modelPolicies key entirely — top-level defaults then apply to every routed model
  4. Type the field as ModelCompactPolicyConfig[] in programmatic config so the compiler rejects non-array shapes

Example fix

# cordis.yml — before (parses as an object)
plugins:
  '@deepseek-ai/dsh-compaction-basic':
    config:
      modelPolicies:
        deepseek:
          model: deepseek-chat
          maxTokens: 16384

# after (array of exact-target overrides)
plugins:
  '@deepseek-ai/dsh-compaction-basic':
    config:
      modelPolicies:
        - provider: deepseek
          model: deepseek-chat
          maxTokens: 16384
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight before booting the plugin:
if (config.modelPolicies !== undefined && !Array.isArray(config.modelPolicies)) {
  throw new TypeError(
    `modelPolicies must be an array, got ${typeof config.modelPolicies}`,
  )
}
const resolved = resolveConfig(config)

Try / catch

try {
  resolveConfig(config)
} catch (err) {
  // Static config failure: report the source and stop; never retry —
  // the same config produces the same throw.
  throw new Error(
    `cordis.yml compaction-basic config invalid: ${(err as Error).message}`,
    { cause: err },
  )
}

Prevention

When it happens

Trigger: A cordis.yml compaction-basic config block (or a programmatic resolveConfig(config) call) supplies modelPolicies as a YAML/JSON mapping instead of a sequence (e.g. modelPolicies: { deepseek: ... }), a scalar, or a single bare object. YAML is the usual culprit: keyed entries under modelPolicies: parse as an object, not a list.

Common situations: Hand-editing cordis.yml and keying policies by provider name (natural for maps elsewhere in the file); copy-pasting a single { provider, model } object without wrapping it in a list; config pipelines re-serializing the array as an object.

Related errors


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