gastownhall/beads · error

legacy SQLite issue waiters serialize to %d bytes (current T

Error message

legacy SQLite issue waiters serialize to %d bytes (current TEXT maximum %d)

What it means

validateCurrentTextBytes also serializes the issue's Waiters list via issueops.FormatJSONStringArray and enforces the same TEXT byte limit. If the serialized waiters JSON exceeds currentTextBytes, the migration rejects the row.

Source

Thrown at internal/migration/legacysqlite/reader.go:683

				return fmt.Errorf("lone high UTF-16 surrogate escape")
			}
			i = next + 5
		case code >= 0xdc00 && code <= 0xdfff:
			return fmt.Errorf("lone low UTF-16 surrogate escape")
		default:
			i += 5
		}
	}
	return nil
}

func validateCurrentTextBytes(issue *types.Issue) error {
	if len(issue.Payload) > currentTextBytes {
		return fmt.Errorf("legacy SQLite issue payload is %d bytes (current TEXT maximum %d)", len(issue.Payload), currentTextBytes)
	}
	waiters := issueops.FormatJSONStringArray(issue.Waiters)
	if len(waiters) > currentTextBytes {
		return fmt.Errorf("legacy SQLite issue waiters serialize to %d bytes (current TEXT maximum %d)", len(waiters), currentTextBytes)
	}
	return nil
}

func decodeWaiters(raw string) ([]string, error) {
	var decoded any
	if err := json.Unmarshal([]byte(raw), &decoded); err != nil {
		return nil, err
	}
	values, ok := decoded.([]any)
	if !ok {
		return nil, fmt.Errorf("must be an array of strings")
	}
	waiters := make([]string, len(values))
	for i, value := range values {
		waiter, ok := value.(string)
		if !ok {
			return nil, fmt.Errorf("element %d is not a string", i)

View on GitHub (pinned to 71377f2769)

Solutions

  1. Reduce the waiter list on the legacy issue before migrating (drop stale waiters).
  2. Increase the target TEXT limit if the schema permits.
  3. Migrate with waiters truncated and re-add waiters post-migration.

Example fix

// before
waiters := issue.Waiters // 10,000 entries migrated as-is
// after
issue.Waiters = issue.Waiters[:maxWaiters]
Defensive patterns

Strategy: validation

Validate before calling

if n := len(issueops.FormatJSONStringArray(issue.Waiters)); n > currentTextBytes { return fmt.Errorf("waiters too large: %d > %d", n, currentTextBytes) }

Try / catch

if err := validateCurrentTextBytes(issue); err != nil { log.Warn("trimming waiters for", issue.ID); issue.Waiters = nil }

Prevention

When it happens

Trigger: len(FormatJSONStringArray(issue.Waiters)) > currentTextBytes during validate().

Common situations: Legacy issues with hundreds/thousands of waiting actors (long waiter lists), producing a JSON array larger than the column limit.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/857bfd06c0e07602. Report an issue: GitHub.