micro/go-micro · error

<joined load errors>

Error message

<joined load errors>

What it means

The memory loader's Load iterates each source, calling its Read and accumulating failures, then calls m.reload() to rebuild the merged value set; any reload error is also appended. If any errors were collected they are joined with newlines into a single error and returned. The message text is the concatenation of all per-source/reload errors, so the root causes are inside the joined string.

Source

Thrown at config/loader/memory/memory.go:354

			continue
		}
		m.Lock()
		m.sources = append(m.sources, source)
		m.sets = append(m.sets, set)
		idx := len(m.sets) - 1
		m.Unlock()
		if !m.opts.WithWatcherDisabled {
			go m.watch(idx, source)
		}
	}

	if err := m.reload(); err != nil {
		gerrors = append(gerrors, err.Error())
	}

	// Return errors
	if len(gerrors) != 0 {
		return errors.New(strings.Join(gerrors, "\n"))
	}
	return nil
}

func (m *memory) Watch(path ...string) (loader.Watcher, error) {
	if m.opts.WithWatcherDisabled {
		return nil, errors.New("watcher is disabled")
	}

	value, err := m.Get(path...)
	if err != nil {
		return nil, err
	}

	m.Lock()

	w := &watcher{
		exit:    make(chan bool),

View on GitHub (pinned to 24529f1404)

Solutions

  1. Read each line of the returned joined error to identify which source(s) failed, then fix that source (path, address, credentials, format).
  2. Validate source files/connections before deployment (parse the JSON/YAML, ping the config server).
  3. Call Load at startup and fail fast instead of continuing with a partially loaded config.
  4. If a source is optional, load it separately and tolerate its failure rather than passing it into the main Load call.

Example fix

// before
loader.Load(fileSrc, etcdSrc) // errors ignored
// after
if err := loader.Load(fileSrc, etcdSrc); err != nil {
    log.Fatalf("config load failed: %v", err) // shows each failing source
}
Defensive patterns

Strategy: try-catch

Validate before calling

for _, s := range sources {
    if _, err := s.Read(); err != nil {
        return fmt.Errorf("source %s unreadable before load: %w", s.String(), err)
    }
}

Try / catch

if err := loader.Load(sources...); err != nil {
    for _, line := range strings.Split(err.Error(), "\n") {
        log.Printf("config source error: %s", line)
    }
    return err
}

Prevention

When it happens

Trigger: loader.Load(sources...) where at least one source.Read fails (file missing, invalid format, connection error) or m.reload() fails after merging (e.g. one source's changeset cannot be applied), producing a multi-line joined error.

Common situations: Pointing config at a file/env/etcd source that doesn't exist or is unreachable in a new environment; a YAML/JSON file with a syntax error among otherwise-valid sources; secrets or permissions changes after a deploy causing one source to fail while others succeed.

Related errors


AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01). Data as JSON: /api/errors/212748371b9ec12e. Report an issue: GitHub.