redis/go-redis · error

errors.New(cmd.val) (dynamic: the server's shutdown reason r

Error message

errors.New(cmd.val) (dynamic: the server's shutdown reason reply is wrapped as the error)

What it means

When the SHUTDOWN command (Shutdown/ShutdownSync) gets a string reply instead of the connection closing, the server did not quit; the reply text is wrapped as the command's error via errors.New(cmd.val). The error message is dynamic — it is whatever reason the server replied with.

Source

Thrown at commands.go:767

}

func (c cmdable) shutdown(ctx context.Context, modifier string) *StatusCmd {
	var args []interface{}
	if modifier == "" {
		args = []interface{}{"shutdown"}
	} else {
		args = []interface{}{"shutdown", modifier}
	}
	cmd := NewStatusCmd(ctx, args...)
	_ = c(ctx, cmd)
	if err := cmd.Err(); err != nil {
		if err == io.EOF {
			// Server quit as expected.
			cmd.err = nil
		}
	} else {
		// Server did not quit. String reply contains the reason.
		cmd.err = errors.New(cmd.val)
		cmd.val = ""
	}
	return cmd
}

func (c cmdable) Shutdown(ctx context.Context) *StatusCmd {
	return c.shutdown(ctx, "")
}

func (c cmdable) ShutdownSave(ctx context.Context) *StatusCmd {
	return c.shutdown(ctx, "save")
}

func (c cmdable) ShutdownNoSave(ctx context.Context) *StatusCmd {
	return c.shutdown(ctx, "nosave")
}

// SlaveOf sets a Redis server as a replica of another, or promotes it to being a master.

View on GitHub (pinned to c5cad058c7)

Solutions

  1. Inspect the error message — it is the server's own reason.
  2. Retry with ShutdownNoSave(ctx) (SHUTDOWN NOSAVE) if a failing persistence save is blocking shutdown.
  3. Check server logs for the underlying persistence/replication failure.
  4. Verify the connection user is allowed to run SHUTDOWN.

Example fix

// before
err := rdb.Shutdown(ctx).Err() // opaque server reason
// after
if err := rdb.Shutdown(ctx).Err(); err != nil {
    // fall back to skipping the save
    err = rdb.ShutdownNoSave(ctx).Err()
}
Defensive patterns

Strategy: try-catch

Try / catch

if err := rdb.Shutdown(ctx).Err(); err != nil {
    // err message is the server's own reason string
    log.Printf("server refused shutdown: %v", err)
    if err2 := rdb.ShutdownNoSave(ctx).Err(); err2 != nil {
        log.Fatalf("shutdown failed: %v", err2)
    }
}

Prevention

When it happens

Trigger: Calling rdb.Shutdown(ctx) or rdb.ShutdownSync(ctx) when the server refuses to shut down, e.g. a failing RDB save blocking SHUTDOWN without SAVE/NOSAVE, or a permission refusal; the string reply carries the reason.

Common situations: Scripting shutdown of instances where a BGSAVE child failed (Redis refuses SHUTDOWN with save pending unless SAVE/NOSAVE is given); connection user lacks SHUTDOWN privileges.


AI-assisted analysis of redis/go-redis@c5cad058c7 (2026-09-01). Data as JSON: /api/errors/802df02dc45571af. Report an issue: GitHub.