deepseek-ai/deepseek-harness · error

${name}.summarizationProvider must be a string

Error message

${name}.summarizationProvider must be a string

What it means

summarizationProvider names the LLM provider used to summarize during compaction. validateSummarizationPair() requires that when the key is present it is a string; numbers, booleans, objects, and null all fail. The key is also bound to the pair rule with summarizationModel (set together, or both empty, or both omitted).

Source

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

  if (compactionRetries !== undefined) {
    assertNonNegativeInteger(`${name}.compactionRetries`, compactionRetries)
  }
  if (maxOverflowRetries !== undefined) {
    assertNonNegativeInteger(`${name}.maxOverflowRetries`, maxOverflowRetries)
  }

  validateSummarizationPair(config, name)
}

/** Require one scope to omit, clear, or replace the summarization target as a pair. */
function validateSummarizationPair(
  config: CompactionPolicyConfig | Record<string, unknown>,
  name: string,
): void {
  const provider = config.summarizationProvider
  const model = config.summarizationModel
  if (provider !== undefined && typeof provider !== 'string') {
    throw new Error(`${name}.summarizationProvider must be a string`)
  }
  if (model !== undefined && typeof model !== 'string') {
    throw new Error(`${name}.summarizationModel must be a string`)
  }
  if (provider === undefined && model === undefined) return
  if (provider === undefined || model === undefined
    || (provider.length === 0) !== (model.length === 0)) {
    throw new Error(
      `${name}: summarizationProvider and summarizationModel must be set together `
      + 'as an empty or non-empty pair',
    )
  }
}

/** Reject stale or misspelled keys before defaults can hide them. */
function validateKeys(config: object, keys: ReadonlySet<string>, name: string): void {
  for (const key of Object.keys(config)) {
    if (!keys.has(key)) throw new Error(`${name}: unknown key "${key}"`)

View on GitHub (pinned to b150a551b8)

Solutions

  1. Set summarizationProvider to a non-empty provider-name string together with summarizationModel
  2. To leave it unset, remove the key entirely; to explicitly clear inheritance in a modelPolicies entry, set both fields to ''
  3. Fix the YAML so the value is a plain string on one line

Example fix

# before — key present but null, and half-set pair
summarizationProvider:
summarizationModel: deepseek-chat

# after — proper non-empty pair
summarizationProvider: deepseek
summarizationModel: deepseek-chat
Defensive patterns

Strategy: type-guard

Type guard

function isOptionalString(v: unknown): v is string | undefined {
  return v === undefined || typeof v === 'string'
}
// usage: isOptionalString(config.summarizationProvider)

Try / catch

try {
  resolveConfig(config)
} catch (err) {
  if ((err as Error).message.includes('summarizationProvider must be a string')) {
    throw new Error(
      `summarizationProvider: expected a provider-name string or omit the key; got ${JSON.stringify(config.summarizationProvider)}`,
      { cause: err },
    )
  }
  throw err
}

Prevention

When it happens

Trigger: cordis.yml 'summarizationProvider:' with no value (YAML null, if it survives the loader as null), a numeric provider id, a boolean, or an inline mapping; programmatic config assigning a non-string variable.

Common situations: Leaving the key empty intending 'unset' — the correct unset is omitting the key; using provider indices/enums from another system; templating that emits null for missing values.

Related errors


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