gastownhall/beads · error
checking %s.content_hash: %w
Error message
checking %s.content_hash: %w
What it means
hasContentHashColumn probes whether the migration cursor table has a content_hash column via `SHOW COLUMNS ... LIKE 'content_hash'`. When that SHOW COLUMNS query itself fails with an error that is NOT a table-does-not-exist error (table-not-exist is deliberately treated as 'false, nil'), the failure is wrapped as `checking <cursor>.content_hash: <cause>`.
Source
Thrown at internal/storage/schema/schema.go:1104
// hasContentHashColumn reports whether the cursor table already carries the
// content_hash column. A not-yet-created table simply reports false.
//
// It probes a single table with SHOW COLUMNS rather than INFORMATION_SCHEMA.COLUMNS,
// whose predicate Dolt does not push down. The LIKE narrows the result set, but
// we still compare the Field name exactly because '_' is a LIKE single-character
// wildcard.
func (m migrationSource) hasContentHashColumn(ctx context.Context, db DBConn) (bool, error) {
//nolint:gosec // G201: m.cursorTable is a hardcoded constant; the LIKE literal is fixed.
rows, err := db.QueryContext(ctx, "SHOW COLUMNS FROM "+m.cursorTable+" LIKE 'content_hash'")
if err != nil {
// SHOW COLUMNS errors on a missing table; the old INFORMATION_SCHEMA
// probe returned count 0 instead. Preserve that: an absent cursor table
// has no content_hash column.
if dberrors.IsTableNotExist(err) {
return false, nil
}
return false, fmt.Errorf("checking %s.content_hash: %w", m.cursorTable, err)
}
defer func() { _ = rows.Close() }()
cols, err := rows.Columns()
if err != nil {
return false, fmt.Errorf("checking %s.content_hash: %w", m.cursorTable, err)
}
// SHOW COLUMNS returns Field, Type, Null, Key, Default, Extra (and possibly
// more on some servers); scan every column into RawBytes and read the first
// ("Field"), which is the column name.
cells := make([]sql.RawBytes, len(cols))
dest := make([]any, len(cols))
for i := range cells {
dest[i] = &cells[i]
}
for rows.Next() {
if err := rows.Scan(dest...); err != nil {
return false, fmt.Errorf("checking %s.content_hash: %w", m.cursorTable, err)View on GitHub (pinned to 71377f2769)
Solutions
- Check the wrapped cause for connection/permission errors and fix connectivity or GRANTs (the DB user needs SHOW/SELECT on the schema).
- If the cause indicates a missing table unexpectedly, verify the cursor table name and that bootstrapSQL ran (CREATE TABLE IF NOT EXISTS).
- Retry the migration on a fresh connection — pooled Dolt sessions can hold stale catalog snapshots after a failed statement.
- Confirm you are on a supported Dolt server version; SHOW COLUMNS behavior differences can cause parse errors.
Example fix
// before
rows, err := db.QueryContext(ctx, "SHOW COLUMNS FROM "+m.cursorTable+" LIKE 'content_hash'")
// after
if err := m.ensureBootstrapTable(ctx, db); err != nil { // CREATE TABLE IF NOT EXISTS first
return false, err
}
rows, err := db.QueryContext(ctx, "SHOW COLUMNS FROM "+m.cursorTable+" LIKE 'content_hash'") Defensive patterns
Strategy: try-catch
Validate before calling
// verify access before bootstrap
rows, err := db.QueryContext(ctx, "SELECT 1 FROM information_schema.tables WHERE table_schema = DATABASE() LIMIT 1")
if err != nil {
return fmt.Errorf("cannot read schema metadata: %w", err)
}
rows.Close() Type guard
func isTableNotExist(err error) bool { return dberrors.IsTableNotExist(err) }
// treat isTableNotExist(err)==true as benign (column absent), everything else needs handling Try / catch
_, err := MigrateUp(ctx, db)
if err != nil && strings.Contains(err.Error(), ".content_hash") {
if !dberrors.IsTableNotExist(errors.Unwrap(err)) {
log.Printf("content_hash probe failed (conn/perm issue): %v — retrying on fresh connection", err)
_, err = MigrateUp(ctx, freshConnDB())
}
} Prevention
- Ensure the app DB user has SHOW/SELECT privileges on the schema.
- Use fresh connections for migration bootstrap; avoid sessions that previously executed failing statements on Dolt.
- Run bootstrapSQL (CREATE TABLE IF NOT EXISTS) before probing cursor columns.
- Match driver and Dolt server versions to supported combinations.
When it happens
Trigger: The `SHOW COLUMNS FROM <cursorTable> LIKE 'content_hash'` query fails for reasons other than a missing table: connection loss, permission denial, a corrupted catalog, or the session being poisoned after a prior failed statement on a pooled Dolt connection.
Common situations: Database user lacks privileges to run SHOW on the schema; transient network drop during bootstrap; Dolt server restarted mid-operation; the query runs against a backend where SHOW COLUMNS syntax/behavior differs.
Related errors
- failed to migrate credential keys: %w
- failed to update encrypted password for peer %s: %w
- failed to initialize schema: %w
- failed to rebuild pool after migration: %w
- ensuring local_metadata: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/3592271085b73ddf.
Report an issue: GitHub.