deepseek-ai/deepseek-harness · error

${name}.summarizationModel must be a string

Error message

${name}.summarizationModel must be a string

What it means

summarizationModel names the model that performs compaction summarization. validateSummarizationPair() requires a string when the key is present; numbers, booleans, arrays, objects, and null all fail. It participates in the same pair rule as summarizationProvider.

Source

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

  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 it to exactly one non-empty model string alongside summarizationProvider
  2. Remove both keys to inherit the effective setting
  3. If you need a different summarization model per route, put the pair in that route's modelPolicies entry

Example fix

# before — list of models
summarizationProvider: deepseek
summarizationModel:
  - deepseek-chat
  - deepseek-reasoner

# after — single string
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.summarizationModel)

Try / catch

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

Prevention

When it happens

Trigger: 'summarizationModel:' with no value (YAML null), a numeric model id, or a list of candidate models (only one string is accepted, no fallback lists).

Common situations: Quoting or id mistakes when templating model names; trying to specify multiple fallback models as a list; assuming a default model fills in when the key is blank.

Related errors


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