gastownhall/beads · error

ExternalDoltConfig: TLSSkipVerify set without TLSRequired

Error message

ExternalDoltConfig: TLSSkipVerify set without TLSRequired

What it means

Validate() rejects TLSSkipVerify=true when TLSRequired is false. TLSSkipVerify is an explicit opt-in to insecure TLS (InsecureSkipVerify in TLSClientConfig), which only exists when TLSRequired is on; setting it on a plaintext config is contradictory and would be silently ignored. Failing loudly prevents operators from believing they disabled certificate verification when TLS was never active.

Source

Thrown at internal/configfile/external_dolt_config.go:89

		return fmt.Errorf("ExternalDoltConfig: TLSCert %q is not absolute", c.TLSCert)
	}
	if c.TLSKey != "" && !filepath.IsAbs(c.TLSKey) {
		return fmt.Errorf("ExternalDoltConfig: TLSKey %q is not absolute", c.TLSKey)
	}
	if c.TLSCACert != "" && !filepath.IsAbs(c.TLSCACert) {
		return fmt.Errorf("ExternalDoltConfig: TLSCACert %q is not absolute", c.TLSCACert)
	}

	if !c.TLSRequired {
		switch {
		case c.TLSCACert != "":
			return errors.New("ExternalDoltConfig: TLSCACert set without TLSRequired")
		case c.TLSCert != "" || c.TLSKey != "":
			return errors.New("ExternalDoltConfig: TLSCert/TLSKey set without TLSRequired")
		case c.TLSServerName != "":
			return errors.New("ExternalDoltConfig: TLSServerName set without TLSRequired")
		case c.TLSSkipVerify:
			return errors.New("ExternalDoltConfig: TLSSkipVerify set without TLSRequired")
		}
	}

	if c.TLSRequired && hasSocket && c.TLSServerName == "" && !c.TLSSkipVerify {
		return errors.New("ExternalDoltConfig: TLSRequired over Socket needs TLSServerName or TLSSkipVerify")
	}

	if c.KeepAlivePeriod < 0 {
		return fmt.Errorf("ExternalDoltConfig: KeepAlivePeriod %s is negative", c.KeepAlivePeriod)
	}

	return nil
}

func (c ExternalDoltConfig) TLSClientConfig() (*tls.Config, error) {
	if !c.TLSRequired {
		return nil, nil
	}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Set TLSRequired: true in the config — skip-verify only applies to a TLS connection.
  2. Remove TLSSkipVerify if the endpoint is plaintext.
  3. Prefer a proper fix over skip-verify: keep TLSRequired true and supply TLSCACert (and TLSServerName) for the self-signed server.

Example fix

// before (YAML)
external:
  host: dolt.internal
  port: 3307
  tls_skip_verify: true
// after
external:
  host: dolt.internal
  port: 3307
  tls_required: true
  tls_skip_verify: true  # dev only; prefer tls_ca_cert in production
Defensive patterns

Strategy: validation

Validate before calling

func validateSkipVerify(cfg configfile.ExternalDoltConfig, allowInsecure bool) error {
	if cfg.TLSSkipVerify && !cfg.TLSRequired {
		return fmt.Errorf("tls_skip_verify requires tls_required: true")
	}
	if cfg.TLSSkipVerify && !allowInsecure {
		return fmt.Errorf("tls_skip_verify not allowed in this environment")
	}
	return cfg.Validate()
}

Try / catch

if err := cfg.Validate(); err != nil {
	if strings.Contains(err.Error(), "TLSSkipVerify set without TLSRequired") {
		// set tls_required: true or drop tls_skip_verify, then retry
	}
	return err
}

Prevention

When it happens

Trigger: Constructing ExternalDoltConfig with TLSSkipVerify=true (tls_skip_verify: true in YAML, or the testing flag left on) while TLSRequired is false, then calling Validate() directly or via buildProxiedServerClientInfo / NewExternalDoltServer / NewExternalDoltServerUOWProvider.

Common situations: Pointing the client at a self-signed-cert server and setting skip-verify first but forgetting tls_required; a test/dev flag (BEADS test configs set TLSSkipVerify) leaking into a production config where tls_required got dropped; copy-pasting a debug config snippet.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/afcfdc293f7deee1. Report an issue: GitHub.