restic/restic · error
double-quoted string not terminated
Error message
double-quoted string not terminated
What it means
Companion of the single-quote check in SplitShellStrings: after end of input the tokenizer still has a double quote open, so the string cannot be split into well-formed arguments and the parse fails.
Source
Thrown at internal/backend/shell_split.go:68
for i, r := range data {
if s.isSplitChar(r) {
if fieldStart >= 0 {
strs = append(strs, data[fieldStart:i])
fieldStart = -1
}
} else if fieldStart == -1 {
fieldStart = i
}
}
if fieldStart >= 0 { // Last field might end at EOF.
strs = append(strs, data[fieldStart:])
}
switch s.quote {
case '\'':
return nil, errors.New("single-quoted string not terminated")
case '"':
return nil, errors.New("double-quoted string not terminated")
}
if len(strs) == 0 {
return nil, errors.New("command string is empty")
}
return strs, nil
}
View on GitHub (pinned to a80be1478a)
Solutions
- Close the double quote: ensure every opening '"' has a matching '"'.
- Prefer single quotes at the outer layer and double quotes inside, or vice versa, to halve the nesting.
- Paste the value into 'printf %s' / a validator to confirm the character counts match.
Example fix
# before restic -o sftp.command='ssh -o ProxyCommand="nc jump 22' -r sftp:host:/repo snapshots # -> double-quoted string not terminated # after restic -o sftp.command='ssh -o ProxyCommand="nc jump 22"' -r sftp:host:/repo snapshots
Defensive patterns
Strategy: validation
Validate before calling
func doubleQuotesBalanced(s string) bool {
var inSingle bool
count := 0
for _, r := range s {
if r == '\'' { inSingle = !inSingle }
if r == '"' && !inSingle { count++ }
}
return count%2 == 0
} Try / catch
args, err := backend.SplitShellStrings(cmd)
if err != nil {
return nil, fmt.Errorf("invalid sftp.command %q: %w", cmd, err) // covers unterminated double quotes
} Prevention
- Minimize nesting layers; prefer single-quoted outer strings in YAML.
- Run config through a YAML linter that flags unbalanced quotes.
When it happens
Trigger: sftp.command values such as 'ssh -o ProxyCommand="nc host 22' (opening double quote never closed), or values mangled by YAML/JSON/config escaping that strips one quote of a pair.
Common situations: Nested quoting through multiple layers (shell -> restic option -> ssh argument); CI pipelines where YAML folding removes quotes; editing options in a UI that trims trailing quote characters.
Related errors
- single-quoted string not terminated
- sftp: invalid format, hostname or path not found
- invalid format, does not start with "sftp:"
- sftp path starts with the tilde (~) character, that fails fo
- command string is empty
AI-assisted analysis of restic/restic@a80be1478a (2026-08-15).
Data as JSON: /api/errors/dc09d517e9914e99.
Report an issue: GitHub.