gastownhall/beads · error

set repo mtime: %w

Error message

set repo mtime: %w

What it means

SetRepoMtimeInTx writes a row into the repo_mtimes cache table (repo_path, jsonl_path, mtime_ns, last_checked) using INSERT ... ON DUPLICATE KEY UPDATE, and wraps any SQL failure with "set repo mtime: %w". This cache lets bd skip re-reading .beads/issues.jsonl when its mtime is unchanged. The error means the underlying Dolt/MySQL statement failed inside the caller's transaction.

Source

Thrown at internal/storage/issueops/bulk_ops.go:436

		`SELECT mtime_ns FROM repo_mtimes WHERE repo_path = ?`, repoPath).Scan(&mtimeNs)
	if err != nil {
		return 0, nil
	}
	return mtimeNs, nil
}

// SetRepoMtimeInTx upserts the mtime cache for a repo path.
func SetRepoMtimeInTx(ctx context.Context, tx *sql.Tx, repoPath, jsonlPath string, mtimeNs int64) error {
	_, err := tx.ExecContext(ctx, `
		INSERT INTO repo_mtimes (repo_path, jsonl_path, mtime_ns, last_checked)
		VALUES (?, ?, ?, NOW())
		ON DUPLICATE KEY UPDATE
			jsonl_path = VALUES(jsonl_path),
			mtime_ns = VALUES(mtime_ns),
			last_checked = NOW()
	`, repoPath, jsonlPath, mtimeNs)
	if err != nil {
		return fmt.Errorf("set repo mtime: %w", err)
	}
	return nil
}

// ClearRepoMtimeInTx removes the mtime cache entry for a repo path.
func ClearRepoMtimeInTx(ctx context.Context, tx *sql.Tx, repoPath string) error {
	// Expand ~ and resolve to absolute path to match stored format.
	absPath := expandAndAbsPath(repoPath)
	_, err := tx.ExecContext(ctx, `DELETE FROM repo_mtimes WHERE repo_path = ?`, absPath)
	if err != nil {
		return fmt.Errorf("clear repo mtime: %w", err)
	}
	return nil
}

func expandAndAbsPath(p string) string {
	if strings.HasPrefix(p, "~") {
		home, err := os.UserHomeDir()

View on GitHub (pinned to 71377f2769)

Solutions

  1. Run the bd schema migrations so the repo_mtimes table exists (bd doctor / migrate).
  2. Retry the enclosing transaction; transient connection or lock-wait errors resolve on retry.
  3. Verify the transaction has not already been rolled back before calling SetRepoMtimeInTx.
  4. Inspect the wrapped %w error: 'table doesn't exist' -> migrate; 'lock wait timeout' -> shorten transaction or check for stuck writers.
  5. Check context cancellation deadlines on the calling sync operation.

Example fix

// before
if err := issueops.SetRepoMtimeInTx(ctx, tx, repoPath, jsonlPath, mtimeNs); err != nil {
    return err // lost transaction already rolled back
}
// after
if err := issueops.SetRepoMtimeInTx(ctx, tx, repoPath, jsonlPath, mtimeNs); err != nil {
    tx.Rollback() // release locks before returning
    return fmt.Errorf("update mtime cache: %w", err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

if err := bdDoctorCheck(); err != nil { /* schema/migration issue */ }
if ctx.Err() != nil { return ctx.Err() }

Try / catch

if err := issueops.SetRepoMtimeInTx(ctx, tx, repoPath, jsonlPath, mtimeNs); err != nil {
    var se *string
    _ = se
    tx.Rollback()
    return fmt.Errorf("mtime cache update failed (will be rebuilt on next sync): %w", err)
}

Prevention

When it happens

Trigger: Calling SetRepoMtimeInTx when: the repo_mtimes table does not exist (schema not migrated), the transaction is already aborted/rolled back, a duplicate-key conflict cannot be resolved (e.g. repo_path uniqueness violation from differently-normalized paths), the context is cancelled, or the DB connection is lost mid-transaction.

Common situations: Running an older database missing the repo_mtimes migration; passing a repoPath whose normalized form collides with another stored entry; long-running transactions timing out; cancelling a sync command mid-flight; DB restart during bulk import.

Related errors


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