gastownhall/beads · error
truncated JSON escape
Error message
truncated JSON escape
What it means
During legacy SQLite migration, checkJSONSurrogates scans issue metadata strings for backslash escapes before they are re-encoded. If the raw string ends with a lone backslash, there is no following escape character, so the string is not valid JSON and the migration aborts with 'truncated JSON escape'. This guards against importing malformed escaped text from a legacy database.
Source
Thrown at internal/migration/legacysqlite/reader.go:644
return checkUTF8(fields...)
}
func checkUTF8(fields ...currentString) error {
for _, field := range fields {
if !utf8.ValidString(field.value) {
return fmt.Errorf("legacy SQLite %s contains invalid UTF-8", field.name)
}
}
return nil
}
func checkJSONSurrogates(raw string) error {
for i := 0; i < len(raw); i++ {
if raw[i] != '\\' {
continue
}
if i+1 >= len(raw) {
return fmt.Errorf("truncated JSON escape")
}
if raw[i+1] != 'u' {
i++
continue
}
if i+6 > len(raw) {
return fmt.Errorf("truncated JSON Unicode escape")
}
code, err := strconv.ParseUint(raw[i+2:i+6], 16, 16)
if err != nil {
return fmt.Errorf("invalid JSON Unicode escape")
}
switch {
case code >= 0xd800 && code <= 0xdbff:
next := i + 6
if next+6 > len(raw) || raw[next] != '\\' || raw[next+1] != 'u' {
return fmt.Errorf("lone high UTF-16 surrogate escape")
}View on GitHub (pinned to 71377f2769)
Solutions
- Inspect the offending legacy row and remove or properly escape the trailing backslash (use '\\\\' in the source data).
- Re-export the legacy database with a tool that produces valid JSON escaping.
- Sanitize string columns before migration, e.g. double any trailing backslash.
Example fix
// before (legacy row value) "note": "saved with trailing slash \\ // after "note": "saved with trailing slash \\\\"
Defensive patterns
Strategy: validation
Validate before calling
if strings.HasSuffix(raw, "\\") { return fmt.Errorf("value ends with a lone backslash: %q", raw) } Type guard
func hasTrailingBackslash(s string) bool { return strings.HasSuffix(s, "\\") } Prevention
- Always produce JSON with a standard encoder, never manual string concatenation
- Validate legacy TEXT columns with a JSON-escape linter before migration
- Reject trailing-backslash strings at export time
When it happens
Trigger: A string column read from the legacy SQLite DB ends with a bare '\' character as the final byte, so raw[i]=='\\' with i+1 >= len(raw).
Common situations: Hand-edited or corrupted legacy rows, data written by tools that escaped improperly, or truncated TEXT values from an old export.
Related errors
- legacy SQLite issue %s has invalid metadata JSON
- legacy SQLite issue %s metadata: %w
- issue %s waiters: invalid JSON
- issue %s waiters: %w
- truncated JSON Unicode escape
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/53768359a04e7b40.
Report an issue: GitHub.