gastownhall/beads · error

ExternalDoltConfig: TLSCACert set without TLSRequired

Error message

ExternalDoltConfig: TLSCACert set without TLSRequired

What it means

The same source->target edge may not appear twice with the same dependency type. validatePublicCreateDependencies deduplicates edges (including the implicit parent edge and waits-for edge) and refuses exact duplicates with this message naming both endpoint IDs, wrapped as ErrValidation. (Same pair with a different type produces a DependencyTypeConflictError instead.)

Source

Thrown at internal/configfile/external_dolt_config.go:83

		return errors.New("ExternalDoltConfig: TLSCert set without TLSKey")
	case c.TLSCert == "" && c.TLSKey != "":
		return errors.New("ExternalDoltConfig: TLSKey set without TLSCert")
	}

	if c.TLSCert != "" && !filepath.IsAbs(c.TLSCert) {
		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

View on GitHub (pinned to 71377f2769)

Solutions

  1. Deduplicate request.Dependencies by (TargetID, Type) before submitting.
  2. Remove the entry duplicating the implicit ParentID edge.
  3. Use a set keyed by source:target:type when building dependencies programmatically.

Example fix

// before
req.Dependencies = []publicops.DependencyInput{{TargetID: "bd-2", Type: types.DepBlocks}, {TargetID: "bd-2", Type: types.DepBlocks}}
// after
req.Dependencies = dedupeDeps(req.Dependencies) // keep one {bd-2, blocks} entry
Defensive patterns

Strategy: validation

Validate before calling

seen := map[string]bool{}
for _, d := range req.Dependencies {
    k := d.TargetID + ":" + string(d.Type)
    if seen[k] { return fmt.Errorf("duplicate dependency %s", d.TargetID) }
    seen[k] = true
}

Try / catch

if err := store.ExecuteCreate(ctx, req); err != nil {
    if errors.Is(err, storage.ErrValidation) && strings.Contains(err.Error(), "duplicate dependency") { /* dedupe and retry submit */ }
    return err
}

Prevention

When it happens

Trigger: ExecuteCreate/ValidatePublicCreateRequest where two Dependencies entries produce an identical (source,target,type) edge — e.g. the same TargetID+Type listed twice, or a dependency duplicating the implicit ParentID edge; check at public_create.go:203.

Common situations: Merging dependency lists from two sources without deduplication; retry logic re-appending dependencies; Reverse flag and normal direction accidentally producing the same pair; batch templates that already embed the parent edge.

Related errors


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