juicedata/juicefs · error

redis parse %s: %s

Error message

redis parse %s: %s

What it means

After normalizing query parameters, newRedisMeta passes the full URL to go-redis's `redis.ParseURL` (pkg/meta/redis.go:141-144). ParseURL validates scheme (redis/rediss/redis-cluster etc.), host, port, and embedded credentials; any failure is wrapped as `redis parse %s: %s`. Unlike the earlier url.Parse check, this validates redis-specific URL semantics (scheme, port range, invalid user info).

Source

Thrown at pkg/meta/redis.go:141

	skipVerify := query.pop("insecure-skip-verify")
	certFile := query.pop("tls-cert-file")
	keyFile := query.pop("tls-key-file")
	caCertFile := query.pop("tls-ca-cert-file")
	tlsServerName := query.pop("tls-server-name")

	// Client-side caching options
	clientCacheStr := query.pop("client-cache")
	clientCache := clientCacheStr != "false" && clientCacheStr != ""
	clientCacheSize := query.getInt("client-cache-size", "client_cache_size", 12800)
	// Default TTL to prevent reading stale cache for a long time when the connection fails.
	clientCacheExpiry := query.duration("client-cache-expire", "client_cache_expire", time.Minute)
	clientCachePreload := query.getInt("client-cache-preload", "client_cache_preload", 0) // may cause conflict
	u.RawQuery = values.Encode()

	hosts := u.Host
	opt, err := redis.ParseURL(u.String())
	if err != nil {
		return nil, fmt.Errorf("redis parse %s: %s", uri, err)
	}
	if opt.TLSConfig != nil {
		opt.TLSConfig.ServerName = tlsServerName // use the host of each connection as ServerName
		opt.TLSConfig.InsecureSkipVerify = skipVerify != ""
		if certFile != "" {
			cert, err := tls.LoadX509KeyPair(certFile, keyFile)
			if err != nil {
				return nil, fmt.Errorf("get certificate error certFile:%s keyFile:%s error:%s", certFile, keyFile, err)
			}
			opt.TLSConfig.Certificates = []tls.Certificate{cert}
		}
		if caCertFile != "" {
			caCert, err := os.ReadFile(caCertFile)
			if err != nil {
				return nil, fmt.Errorf("read ca cert file error path:%s error:%s", caCertFile, err)
			}
			caCertPool := x509.NewCertPool()
			caCertPool.AppendCertsFromPEM(caCert)

View on GitHub (pinned to c9a67b23e8)

Solutions

  1. Use a supported scheme: `redis://`, `rediss://` (TLS), or `redis-cluster://`/`rediss-cluster://` as supported by your client version.
  2. Fix the port to a numeric value in 1-65535 (default 6379 may be omitted).
  3. Percent-encode username/password correctly (`%40` for `@`, `%25` for `%`); avoid malformed escapes.
  4. For sentinel deployments, do not encode sentinel addresses in the URL; configure them via query/addr format the driver expects.

Example fix

// before
juicefs mount redis-sentinel://mypass@sentinel:26379/1 /jfs // unsupported scheme for ParseURL
// after
juicefs mount redis://mypass@sentinel:26379/1 /jfs
Defensive patterns

Strategy: validation

Validate before calling

// validate redis URL semantics before use
u, _ := url.Parse(metaURL)
if !strslice.Contains(u.Scheme, []string{"redis", "rediss", "redis-cluster", "rediss-cluster"}) {
	return fmt.Errorf("unsupported redis scheme %q", u.Scheme)
}
if p := u.Port(); p != "" {
	if n, err := strconv.Atoi(p); err != nil || n < 1 || n > 65535 { return fmt.Errorf("bad port %q", p) }
}

Try / catch

if err != nil && strings.Contains(err.Error(), "redis parse ") {
	return fmt.Errorf("redis URL rejected by go-redis ParseURL, check scheme/port/userinfo: %w", err)
}

Prevention

When it happens

Trigger: Using a scheme go-redis does not accept (e.g. `redis-sentinel://` where unsupported by ParseURL), an unparseable port (non-numeric or out of range), or a URL whose user-info cannot be decoded — even though generic url.Parse succeeded.

Common situations: Typing `redis://host:port` literally with a placeholder port; using the wrong scheme for the deployment (sentinel/cluster URLs vs plain redis); percent-encoded password containing malformed escapes like `%zz`.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


AI-assisted analysis of juicedata/juicefs@c9a67b23e8 (2026-09-06). Data as JSON: /api/errors/4ea8c02f30a9aaab. Report an issue: GitHub.