ory/kratos · error

configuration value is not a valid URL

Error message

configuration value is not a valid URL: %s

What it means

Config.ParseURI delegates to ParseAbsoluteOrRelativeURI and then additionally requires the parsed URL to have a non-empty scheme. If the value parses as a URI but has no scheme (e.g. 'localhost:5432/db' or a bare path), this error is thrown because the library needs an absolute URL with an explicit scheme to know which driver/protocol to use.

Solutions

  1. Add the correct scheme to the configured URL, e.g. 'postgres://host/db', 'mysql://host/db', or 'sqlite://file?mode=rwc'.
  2. Check env var or YAML for a lost 'scheme://' prefix after templating or secret substitution.
  3. Consult the driver docs for the exact accepted DSN format and copy a known-good example.
  4. Pre-validate the value with url.Parse and check u.Scheme != "" before setting it in config.

Example fix

// before
DSN=postgres://
DSN=localhost:5432/kratos

// after
DSN=postgres://localhost:5432/kratos?sslmode=disable
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.ParseRequestURI(cfg.DSN)
if err != nil {
    return err
}
if u.Scheme == "" {
    return fmt.Errorf("DSN %q must include a scheme (e.g. postgres://)", cfg.DSN)
}

Prevention

When it happens

Trigger: Calling (p *Config).ParseURI(rawUrl) where rawUrl passes URI parsing but parsed.Scheme == "" — e.g. dsn set to 'localhost:5432/db?sslmode=disable' or 'mydb.sqlite' without a 'sqlite://' prefix, or a DSN that lost its 'postgres://' prefix.

Common situations: Migrating from a driver that accepted bare host strings, config templates where the scheme portion was accidentally deleted, or users writing 'sqlite:./db.sqlite' variants the parser treats as scheme-less.

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 ory/kratos@b86338da04 (2026-09-07). Data as JSON: /api/errors/b1272c826c48ee72. Report an issue: GitHub.

Appendix: source

Thrown at driver/config/config.go:1333

	parsed, err := url.ParseRequestURI(u)
	if err != nil {
		return nil, errors.Wrapf(err, "configuration value not a valid URL: %s", rawUrl)
	}

	if frag != "" {
		parsed.Fragment = frag
	}

	return parsed, nil
}

func (p *Config) ParseURI(rawUrl string) (*url.URL, error) {
	parsed, err := p.ParseAbsoluteOrRelativeURI(rawUrl)
	if err != nil {
		return nil, err
	}
	if parsed.Scheme == "" {
		return nil, errors.Errorf("configuration value is not a valid URL: %s", rawUrl)
	}
	return parsed, nil
}

func (p *Config) Tracing(ctx context.Context) *otelx.Config {
	return p.GetProvider(ctx).TracingConfig("Ory Kratos")
}

func (p *Config) IsInsecureDevMode(ctx context.Context) bool {
	return p.GetProvider(ctx).Bool("dev")
}

func (p *Config) IsBackgroundCourierEnabled(ctx context.Context) bool {
	return p.GetProvider(ctx).Bool("watch-courier")
}

func (p *Config) CourierExposeMetricsPort(ctx context.Context) int {
	return p.GetProvider(ctx).Int("expose-metrics-port")

View on GitHub (pinned to b86338da04)