DeepSeek Harness titles stuck at maxOutputTokens 64
A title that stays at the truncated first message usually means the title request's output budget was consumed by reasoning, not that the model cannot write titles. The built-in title plugin reuses the main chat model for a separate request, and max_tokens is a shared budget for reasoning and text. A forced-reasoning model fills it before producing any content; the plugin then throws in the max-tokens branch and logs only a warn, so the UI shows nothing (Discussion #10129).
The reproduction in the thread is the 0.2.1-rc.2 desktop build, and the source references come from a community review. Line numbers may shift between versions, so judge by the config keys and the warn text rather than by line number alone.
DeepSeek Harness session titles: why 64 is the total budget
The number 64 is not in the plugin source but in the bundle's patch config, which makes it a configuration problem you can fix today. The community source review gives four links in the chain:
packages/session/session-title-llm/src/index.ts:84declaresmaxOutputTokensasz.number().step(1).min(1).required(); it is required and has no default.packages/experimental/session-titles-bundle/cordis.patch.yml:10-11suppliesmaxInputBytes: 4096andmaxOutputTokens: 64, and the plugin takes both as given.- A forced-reasoning model spends all 64 tokens on reasoning, so
finish_reasonbecomeslengthandcontentis empty. session-title-llmthrowstitle output reached maxOutputTokensin the max-tokens branch at:202; the error is warned in the catch only and never written to the session event stream.
The thread's measurements make the arithmetic visible: at max_tokens=64, reasoning_tokens=64 and the content is empty; at 1024, reasoning_tokens=139 and the title comes through; at 1024 with no thinking level, reasoning_tokens=0 and the total is 9 tokens. The default of 64 assumes the model does not think; it is not a judgment that a five-word title is enough.
DeepSeek Harness: three steps to confirm the budget, not the model
Use observable evidence to rule out model quality before touching configuration. All three steps run locally:
- Create a session, send one message, run two turns, then look at the sidebar title. Expected: it is still the truncated first message, with no error shown.
- Open the current profile's
cordis.patch.ymland search forsession-titles. Expected: the same block containsmaxOutputTokens: 64andmaxInputBytes: 4096, which shows the bundle patch is in effect rather than plugin defaults. - Send a manual request with
max_tokens: 64and a thinking level, and recordfinish_reasonandreasoning_tokens. Expected:finish_reason=length,reasoning_tokens=64, andcontentempty, matching the title plugin's failure path exactly.
If all three line up, stop suspecting the model or the network; the budget is the problem.
DSH plugin path 1: raise maxOutputTokens in cordis.patch.yml
This is the smallest, fastest change, and it affects only the title request, not the main chat model. Steps:
- Find the session-titles block in the bundle patch and note its plugin id. Expected: an id that a user-level patch can match.
- Add an override block with the same id in the user-level
cordis.patch.yml, raise the budget, and restatemaxInputBytes:
#Override by the same id as the bundle patch; config is replaced as a block
- id: <the plugin id for session-titles>
config:
maxInputBytes: 4096
maxOutputTokens: 1024
- Save, reload the profile, create a session, and run two turns. Expected: the sidebar shows a short model-generated title instead of the truncated first message.
- Check the session event stream again for
title output reached maxOutputTokens. Expected: the warn is gone and the title request finishes normally.
Know the limits of this path: the patch does not deep-merge, so omitting maxInputBytes turns 4096 into unset, and sessions already carrying a fallback title are not recomputed because the fallback is not an anchor for later requests.
DeepSeek Harness path 2: keep the title request from thinking
The idea is to leave all 64 tokens for visible text, but according to the thread it cannot be done through configuration alone. The plugin reuses the main chat model, hardcodes the thinking level to the first list entry, and strips an explicit off entry before sending; the server answers off with 400 and error code 11150, as measured by the reporter. Two workable options remain:
- Give titles a separate small model that does not force reasoning. Expected: with the same 64-token budget,
reasoning_tokens=0and the title returns normally. This needs plugin support for a title model distinct from the chat model. - Change the plugin so the thinking level is configurable, or so an off value survives in the title request. Expected: the request is no longer forced to think and
contentis non-empty. - Re-run step 3 from Path 1 after the change. Expected:
finish_reason=stop, non-empty content, and an updated title.
Without code changes this path is closed; use Path 1 or Path 3 instead.
DeepSeek Harness path 3: switch to local truncated titles
No model call means no budget problem, at the cost of a title that reflects only the first message. This fits setups where titles are just session labels and do not need semantic summarization:
- Disable the session-titles line in the user-level patch, using the
disabledform that the current host's patch schema expects. Expected: no title requests after restart and no title-related warns in the log. - Confirm the sidebar title falls back to the truncated first message. Expected: new titles are stable and predictable but never change with the conversation.
- If the truncated text is too long or contains line breaks, write a small plugin that generates a local title at session creation with whitespace collapsing and a fixed length. Expected: uniform title length and zero token cost.
The trade-off is direct: zero cost and zero failures, but no semantic title. If you run many sessions in parallel and navigate by title, Path 1 is still the better choice; if you want a third-party title plugin, check its host compatibility on DSH Plugin Hub.
DeepSeek Harness: choosing a path and what to check afterwards
Prefer Path 1 for new sessions, Path 2 for plugin developers, and Path 3 when you only need stable readable labels. Finish with these checks in order:
- Restart the profile after changing configuration rather than refreshing the page. Expected: the patch is reloaded and the old 64 is no longer live.
- Create a session and verify title generation. Expected: a semantic title appears within two turns.
- Send a long message that pushes input past 4096 bytes and run another turn. Expected: if titles stop updating, the limit you hit is
maxInputBytes, not the output budget, and you need Path 3 or a different input policy.
According to the thread, the three problems — too small a budget, throwing instead of trimming on overflow, and silent failure — are independent defects. Raising the budget fixes only the first. Lasting stability also needs an input policy that sends a few recent messages with truncation, and a failure that is visible in the UI.
The paths compare as follows:
| Path | Where you change it | Scope | Main limit |
|---|---|---|---|
| Raise the budget | user-level cordis.patch.yml | title requests only | long sessions still hit 4096 bytes |
| Disable thinking | plugin code or a title model | title requests only | not possible through config alone, per the thread |
| Local truncation | disable the plugin or write one | all sessions | titles carry no semantics |
If you only want new sessions to show a title, Path 1 is enough. If long sessions must keep their titles, handle input trimming as well, because a larger budget returns to the same wall as the conversation grows.
Whichever path you take, add one observable check: clear the existing title, trigger a title request, and look for a success record in the session event stream. If there is no record, the failure is still silent and the fix is only half done.
Source: Discussion #10129, deepseek-ai/deepseek-harness. For more entry points, see DSH troubleshooting.
FAQ
DeepSeek Harness spends the title request's output budget on reasoning. The title plugin sets maxOutputTokens to 64, and max_tokens covers reasoning plus visible text. A forced-reasoning model spends all 64 tokens on reasoning, leaves the content empty, and hits the max-tokens branch, which only logs a warn. Nothing appears in the UI.
DeepSeek Harness restores titles for new sessions when the budget is raised. Override maxOutputTokens by the same plugin id in the user-level cordis.patch.yml, but the patch replaces the config block instead of deep-merging it, so restate maxInputBytes in the same block. Existing fallback titles do not heal themselves and change only after the next successful request.
According to the thread, the DeepSeek Harness title plugin hardcodes the thinking level to the first entry in a list and removes an explicit off entry before sending. The server answers off with 400 and error code 11150. The path therefore cannot be completed by configuration alone: either give titles a model that does not force reasoning, or change the plugin so the level is configurable.
DeepSeek Harness still stops updating titles in long sessions because maxInputBytes defaults to 4096 bytes and the title plugin resends every user message, so input grows monotonically and throws instead of trimming. A budget of 1024 is only a stopgap; long sessions need an input policy that sends a few recent messages with truncation.
Related Terms
- maxOutputTokens
- maxOutputTokens is the total token budget allowed for one model request. Reasoning and visible text share it; it is not a budget for the answer alone.— https://github.com/deepseek-ai/deepseek-harness/discussions/10129
- max-tokens branch
- The max-tokens branch is the title plugin's failure path when finish_reason is length. It throws title output reached maxOutputTokens and records only a warn in the catch block.— https://github.com/deepseek-ai/deepseek-harness/discussions/10129
- cordis.patch.yml
- cordis.patch.yml is the DSH patch file that overrides plugin configuration. It matches a plugin id and replaces the whole config block without field-level deep merge, so other fields in the block must be restated.— https://github.com/deepseek-ai/deepseek-harness/discussions/10129
- fallback title
- A fallback title is the truncated first message that the title plugin writes to the session record when the model request fails. It is persisted as the real title and is not used as an anchor for the next request.— https://github.com/deepseek-ai/deepseek-harness/discussions/10129