go-redis/redis · error

failed to authenticate: %w

Error message

failed to authenticate: %w

What it means

Thrown when HELLO negotiation fell back (server does not support HELLO) and the legacy AUTH/AUTH ACL fallback then failed. This only runs when a password is set: the client tries HELLO first, and on rejection issues AUTH; if AUTH itself errors, the connection is closed and wrapped with this message.

Source

Thrown at redis.go:817

		// the server does not support the HELLO command.
		// The server may be a redis-server that does not support the HELLO command,
		// or it could be DragonflyDB or a third-party redis-proxy. They all respond
		// with different error string results for unsupported commands, making it
		// difficult to rely on error strings to determine all results.
		cn.GetStateMachine().Transition(pool.StateClosed)
		return initErr
	} else {
		helloFallbackToRESP2 = c.opt.Protocol == 3
		if password != "" {
			// Try legacy AUTH command if HELLO failed.
			if username != "" {
				initErr = conn.AuthACL(ctx, username, password).Err()
			} else {
				initErr = conn.Auth(ctx, password).Err()
			}
			if initErr != nil {
				cn.GetStateMachine().Transition(pool.StateClosed)
				return fmt.Errorf("failed to authenticate: %w", initErr)
			}
		}
	}
	if helloFallbackToRESP2 {
		c.disableCSCServing(ctx, "HELLO 3 was rejected and the connection negotiated RESP2")
	}

	// trackingEnabled reports whether THIS pool connection must issue
	// CLIENT TRACKING ON during init. True when CSC (SharedTracking) is enabled:
	// the shared cache is fed by per-connection tracking + the background
	// drainer. Once CSC serving stops (owner Close, GC cleanup, or drainer
	// damping), new and re-inited conns skip tracking — nothing consumes the
	// pushes into the cache anymore.
	trackingEnabled := !helloFallbackToRESP2 && !cn.IsPubSub() && c.cscTrackingRequested()
	if trackingEnabled && c.cscConnInitGen(cn.GetID()) == 0 {
		// First initialization establishes generation 1. Reinitialization
		// already bumped and evicted through onCscReinit before replacing the
		// socket, so it must not bump a second time here.

View on GitHub (pinned to 36d97525cd)

Solutions

  1. Verify the password is correct with redis-cli AUTH (or AUTH user pass for ACL).
  2. If using ACL, confirm the user exists and has permissions on the target DB (ACL GETUSER).
  3. Check for shell/config escaping issues around special characters in the password.
  4. If the password is correct, ensure the server actually requires legacy AUTH (older server) vs. HELLO-based auth.

Example fix

// before
opt := &redis.Options{Addr: addr, Username: "app", Password: wrongPass}

// after
opt := &redis.Options{Addr: addr, Username: "app", Password: correctPass}
Defensive patterns

Strategy: validation

Validate before calling

// Verify credentials out-of-band before relying on the client.
rc := redis.NewClient(&redis.Options{Addr: addr, Username: user, Password: pass})
if err := rc.Ping(ctx).Err(); err != nil {
    return fmt.Errorf("auth pre-check failed: %w", err)
}
rc.Close()

Try / catch

if err := client.Ping(ctx).Err(); err != nil {
    var pe *redis.errorString // go-redis may expose auth error helpers
    if redis.IsAuthErr(err) || strings.Contains(err.Error(), "WRONGPASS") {
        // surface as a credential problem
    }
}

Prevention

When it happens

Trigger: Server rejects HELLO (older redis-server < 6, or DragonflyDB/proxy without HELLO) AND Password != "" AND the subsequent AUTH (or AUTH ACL when Username is also set) returns a redis error such as WRONGPASS or invalid username.

Common situations: Wrong password configured; ACL user deleted or disabled; connecting with a Username to a server that requires AUTH without username but the password is wrong; password contains characters that were mangled by shell/config escaping; rotated credential not yet propagated.

Related errors


AI-assisted analysis of go-redis/redis@36d97525cd (2026-08-06). Data as JSON: /data/errors/c420f1ac0889e83c.json. Report an issue: GitHub.