goharbor/harbor · critical
invalid redis URL
Error message
invalid redis URL
What it means
Harbor job service configuration error thrown from Config.validate() (src/jobservice/config/config.go:349) when the worker pool backend is 'redis' but RedisPoolCfg.RedisURL contains no '://' scheme separator. The service refuses to start because the Redis pool needs a full URL to dial. Note that the normal YAML/env load path auto-prepends 'redis://' to scheme-less addresses (config.go:172-183), so this variant mainly fires when a Config struct is built programmatically and validated directly, or when the later url.Parse fails (that sibling case reports 'invalid redis URL: %s').
Source
Thrown at src/jobservice/config/config.go:349
if c.PoolConfig == nil {
return errors.New("no worker worker is configured")
}
if c.PoolConfig.Backend != JobServicePoolBackendRedis {
return fmt.Errorf("worker worker backend %s does not support", c.PoolConfig.Backend)
}
// When backend is redis
if c.PoolConfig.Backend == JobServicePoolBackendRedis {
if c.PoolConfig.RedisPoolCfg == nil {
return fmt.Errorf("redis worker must be configured when backend is set to '%s'", c.PoolConfig.Backend)
}
if utils.IsEmptyStr(c.PoolConfig.RedisPoolCfg.RedisURL) {
return errors.New("URL of redis worker is empty")
}
if !strings.Contains(c.PoolConfig.RedisPoolCfg.RedisURL, "://") {
return errors.New("invalid redis URL")
}
if _, err := url.Parse(c.PoolConfig.RedisPoolCfg.RedisURL); err != nil {
return fmt.Errorf("invalid redis URL: %s", err.Error())
}
if utils.IsEmptyStr(c.PoolConfig.RedisPoolCfg.Namespace) {
return errors.New("namespace of redis worker is required")
}
}
// Job service loggers
if len(c.LoggerConfigs) == 0 {
return errors.New("missing logger config of job service")
}
// Job loggers
if len(c.JobLoggerConfigs) == 0 {View on GitHub (pinned to 7b2fd08cc5)
Solutions
- Write the URL with an explicit scheme: redis://:password@host:6379/0 (rediss:// for TLS)
- Prefer loading config through config.Load from YAML/env — it prepends redis:// to scheme-less addresses before validating
- Check the effective value of JOB_SERVICE_POOL_REDIS_URL / jobservice.pool.redis_url inside the jobservice container
- If Redis was not intended, set the pool backend to 'database' and drop the Redis pool config
Example fix
// before cfg.PoolConfig.RedisPoolCfg.RedisURL = "redis:6379" // after cfg.PoolConfig.RedisPoolCfg.RedisURL = "redis://:password@redis:6379/0"
Defensive patterns
Strategy: validation
Validate before calling
func checkRedisURL(raw string) error {
if !strings.Contains(raw, "://") {
return fmt.Errorf("redis URL %q must include a scheme (redis:// or rediss://)", raw)
}
if _, err := url.Parse(raw); err != nil {
return fmt.Errorf("redis URL does not parse: %w", err)
}
return nil
} Type guard
func isSchemedRedisURL(raw string) bool {
return strings.Contains(raw, "://")
} Prevention
- Load config through config.Load (YAML/env) so scheme-less Redis addresses are auto-prefixed with redis://
- Add a CI step that runs Config.Validate() on the rendered config before deploying
- Standardize on redis://…/rediss:// forms in every environment
When it happens
Trigger: Calling Load/Validate on a Config with PoolConfig.Backend == JobServicePoolBackendRedis and RedisPoolCfg.RedisURL like 'redis:6379' or 'myredis:6379' (no scheme); constructing the config by hand in tests or embedded jobservice use instead of going through the YAML loader; env JOB_SERVICE_POOL_REDIS_URL set to a scheme-less host:port in a code path that skips the translate step.
Common situations: Older docs/examples showing host:port form; Helm values injecting a scheme-less URL into a custom image; unit tests constructing Config directly; copy-paste of 'redis:6379' from docker-compose service names.
Related errors
- namespace of redis worker is required
- URL of redis worker is empty
- missing logger config of job service
- missing logger config of job
- bad redis url for registry:%s
AI-assisted analysis of goharbor/harbor@7b2fd08cc5 (2026-08-16).
Data as JSON: /api/errors/c918cebc0b8908c1.
Report an issue: GitHub.