{"record":{"id":"95f763c26afa8199","repo":"gitbutlerapp/gitbutler","slug":"the-model-returned-no-reasoning-for","errorCode":null,"errorMessage":"The model returned no reasoning for \"{}\"","messagePattern":"The model returned no reasoning for \"(.+?)\"","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/but-api/src/resolve/mod.rs","lineNumber":640,"sourceCode":"            );\n        };\n        if resolved_files[index].is_some() {\n            bail!(\n                \"The model returned more than one resolution for \\\"{}\\\"\",\n                resolution.path\n            );\n        }\n        let file = &request.files[index];\n        if resolution.hunks.len() != file.hunks.len() {\n            bail!(\n                \"The model returned {} resolved hunks for \\\"{}\\\" but the file has {} conflicts\",\n                resolution.hunks.len(),\n                file.path,\n                file.hunks.len()\n            );\n        }\n        if resolution.reasoning.trim().is_empty() {\n            bail!(\"The model returned no reasoning for \\\"{}\\\"\", file.path);\n        }\n        for (hunk_index, hunk) in resolution.hunks.iter().enumerate() {\n            apply::ensure_no_markers(&hunk.resolved_content, &file.path)?;\n            picks[index].insert(\n                hunk_index,\n                apply::HunkPick::Content(hunk.resolved_content.clone()),\n            );\n        }\n        resolved_files[index] = Some(ResolvedFile {\n            path: file.path.clone(),\n            hunks: resolution\n                .hunks\n                .iter()\n                .map(|hunk| hunk.resolved_content.clone())\n                .collect(),\n            reasoning: resolution.reasoning.clone(),\n        });\n    }","sourceCodeStart":622,"sourceCodeEnd":658,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-api/src/resolve/mod.rs#L622-L658","documentation":"Every per-file resolution from the model must include non-empty `reasoning` (trimmed). GitButler requires the model to justify each resolution so it can be surfaced to the user; an empty or whitespace-only reasoning string fails the whole response. This is a contract of ResolutionResponse, not a nicety.","triggerScenarios":"The model omits the reasoning field, outputs an empty string, or fills it with whitespace/newlines only. Providers whose structured-output enforcement is lax are the usual source; small local models often skip optional-looking text fields.","commonSituations":"Local/small models via custom providers; schema-optional JSON modes; reasoning hidden behind a provider flag and serialized as an empty string.","solutions":["Let the single automatic retry run - second samples usually include reasoning","Use a model/provider combination that reliably fills structured text fields","If you inject resolutions via resolve_commit_conflicts_with (tests, custom frontends), always populate a non-empty reasoning per file"],"exampleFix":"// before (custom resolver injected into resolve_commit_conflicts_with)\nreturn { resolutions: files.map(f => ({ path: f.path, hunks: [...], reasoning: ' ' })), summary: '' };\n\n// after\nreturn { resolutions: files.map(f => ({ path: f.path, hunks: [...], reasoning: 'Took theirs: our side only deleted a comment.' })), summary: 'Resolved all files.' };","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await api.resolveCommitConflictsAi(commitId);\n} catch (err) {\n  if (String(err).includes('no reasoning')) {\n    await api.resolveCommitConflictsAi(commitId); // second sample usually fills reasoning\n  } else throw err;\n}","preventionTips":["When injecting resolutions yourself, always fill reasoning with a real sentence per file - empty strings are rejected","Choose providers that enforce structured output schemas including text fields","Do not treat reasoning as optional; it is validated like the content itself"],"tags":["ai-resolution","llm-validation","missing-field","resolve-api"],"backgroundTag":"llm-response-validation-failed","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}