{"record":{"id":"0c171dc109d17186","repo":"gitbutlerapp/gitbutler","slug":"unterminated-quoted-message","errorCode":null,"errorMessage":"unterminated quoted message","messagePattern":"unterminated quoted message","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/but-workspace/src/branch/integrate_branch_upstream/parsing.rs","lineNumber":217,"sourceCode":"        }\n\n        match ch {\n            '\\\\' => escaped = true,\n            '\"' => {\n                let trailing = input[index + ch.len_utf8()..].trim();\n                if trailing.is_empty() {\n                    return Ok(output);\n                }\n                bail!(\"unexpected trailing characters after quoted message\");\n            }\n            other => output.push(other),\n        }\n    }\n\n    if escaped {\n        bail!(\"unterminated escape sequence in quoted message\");\n    }\n    bail!(\"unterminated quoted message\")\n}\n\nfn quote_message(message: &str) -> String {\n    let mut out = String::from(\"\\\"\");\n    for ch in message.chars() {\n        match ch {\n            '\\\\' => out.push_str(\"\\\\\\\\\"),\n            '\"' => out.push_str(\"\\\\\\\"\"),\n            '\\n' => out.push_str(\"\\\\n\"),\n            '\\r' => out.push_str(\"\\\\r\"),\n            '\\t' => out.push_str(\"\\\\t\"),\n            other => out.push(other),\n        }\n    }\n    out.push('\"');\n    out\n}\n","sourceCodeStart":199,"sourceCodeEnd":235,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-workspace/src/branch/integrate_branch_upstream/parsing.rs#L199-L235","documentation":"Raised by `parse_quoted_string` when the whole message clause is consumed without ever finding a closing double quote. The opening quote was seen, but the string literal never terminates on that line.","triggerScenarios":"Lines like `squash 4f2a 991b | message=\"unfinished` — missing close quote, possibly because the message itself contains an unescaped `\"` that closed it early and left the rest dangling, or the line was cut short.","commonSituations":"User omits the closing quote; newline intended inside the message must be written as the literal `\\n` escape (raw multi-line messages are impossible since the grammar is line-based); unescaped inner quote ends the literal prematurely.","solutions":["Close the string: `| message=\"finished\"`.","Escape any inner double quote as `\\\"` and express newlines as `\\n`, not actual line breaks.","Regenerate the line with the same rules `quote_message` uses when in doubt."],"exampleFix":"# before\nsquash 4f2a 991b | message=\"combine \"fixes\" and more\n\n# after\nsquash 4f2a 991b | message=\"combine \\\"fixes\\\" and more\"","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":"if let Err(err) = parse_integration_steps_script(&script, &divergence) {\n    if err.to_string().contains(\"unterminated quoted message\") {\n        // missing close quote or unescaped inner quote; newlines must be literal \\n\n    }\n}","preventionTips":["Escape inner double quotes as \\\"; write newlines as \\n (raw multi-line messages are not supported).","Let the UI generate the clause from a plain-text message field instead of free-form editing."],"tags":["rust","git","but-workspace","integration","todo-script","parsing","quoting"],"backgroundTag":"unterminated-string-literal","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}