go-redis/redis · error

failed to resolve credentials: %w

Error message

failed to resolve credentials: %w

What it means

Thrown during per-connection initialization on the non-streaming path when Options.resolveCredentials(ctx) fails. This resolves credentials from context-based provider, function provider, or static Username/Password; failure means none of those sources could produce usable credentials, so the connection is closed and the error propagates.

Source

Thrown at redis.go:779

		// the pre-fix wrappedOnClose approach — build an unbounded closure chain
		// retaining every prior connection's unsubscribe (see issue #3772).
		//
		// Note: pool.Conn.SetOnClose OVERWRITES any prior callback (see the
		// doc on that method). That is safe here because the streaming
		// credentials Manager deduplicates listeners by connection id, so a
		// second initConn on the same cn re-Subscribes the SAME listener and
		// the returned unsubscribe is equivalent to the one already installed.
		// Any future code path that could hand out a distinct unsubscribe on
		// re-initialization must first invoke the existing one to avoid
		// orphaning the old subscription on the credentials provider.
		cn.SetOnClose(unsubscribeFromCredentialsProvider)

		username, password = credentials.BasicAuth()
	} else {
		username, password, initErr = c.opt.resolveCredentials(ctx)
		if initErr != nil {
			cn.GetStateMachine().Transition(pool.StateClosed)
			return fmt.Errorf("failed to resolve credentials: %w", initErr)
		}
	}

	// for redis-server versions that do not support the HELLO command,
	// RESP2 will continue to be used.
	// helloOK tracks whether HELLO succeeded. If it did not, the connection
	// falls back to RESP2 regardless of c.opt.Protocol, and features that
	// require RESP3 (e.g. maintenance notifications) must be skipped.
	helloOK := false
	// For redis-server versions that do not support HELLO, RESP2 continues to
	// be used. Remember that negotiated fallback: configured Protocol remains 3,
	// but CSC must not serve without RESP3 invalidations.
	helloFallbackToRESP2 := false
	if initErr = conn.Hello(ctx, c.opt.Protocol, username, password, c.opt.ClientName).Err(); initErr == nil {
		// Authentication successful with HELLO command
		helloOK = true
	} else if !isRedisError(initErr) {
		// When the server responds with the RESP protocol and the result is not a normal

View on GitHub (pinned to 36d97525cd)

Solutions

  1. Confirm static Username/Password are correct and the ACL user exists on the server (redis-cli ACL GETUSER).
  2. If using CredentialsProvider/CredentialsProviderFunc, ensure it returns (user, pass, nil) and does not depend on a cancelled context.
  3. Test the secret source (Vault, SM, env var) independently to confirm it returns the credential.
  4. Temporarily hardcode known-good credentials to isolate whether the failure is in resolution vs. the server.

Example fix

// before
opt.CredentialsProviderFunc = func(ctx context.Context) (string, string, error) {
    return "", "", fmt.Errorf("vault unreachable")
}

// after
opt.CredentialsProviderFunc = func(ctx context.Context) (string, string, error) {
    u, p, err := vault.GetRedisCreds(ctx)
    if err != nil { return "", "", err }
    return u, p, nil
}
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight the static or function-based credentials against the server.
user, pass, err := opt.resolveCredentials(ctx)
if err != nil {
    return fmt.Errorf("credentials resolve pre-check failed: %w", err)
}

Try / catch

if err := client.Ping(ctx).Err(); err != nil {
    if strings.Contains(err.Error(), "failed to resolve credentials") {
        // re-resolve or surface to operator
    }
}

Prevention

When it happens

Trigger: No StreamingCredentialsProvider set, but a CredentialsProvider (context), a CredentialsProviderFunc, or static Username/Password returned an error during dial. Occurs on the initial connection and on every reconnect since initConn re-runs resolution.

Common situations: Static password is empty/unset on a server requiring AUTH (NOAUTH); ACL user does not exist; CredentialsProviderFunc panics or returns an error; the context passed to credentials resolution was cancelled/expired; secret manager (Vault/AWS Secrets Manager) call failed.

Related errors


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