chenhg5/cc-connect · error

relay: target engine %q not found (is the project running?)

Error message

relay: target engine %q not found (is the project running?)

What it means

Thrown by RelayManager.Send when req.To is bound in the chat but rm.engines has no engine registered under that project name — i.e. the target project's Engine isn't running or wasn't registered with the RelayManager. Binding and engine registration are separate concerns; this error catches the gap.

Source

Thrown at core/relay.go:231

	targetEngine := rm.engines[req.To]
	sourceEngine := rm.engines[req.From]
	visibility := rm.visibility
	rm.mu.RUnlock()

	if binding == nil {
		return nil, fmt.Errorf("relay: no binding for this chat. Use /bind <project> first")
	}
	if _, ok := binding.Bots[req.To]; !ok {
		var bound []string
		for proj := range binding.Bots {
			if proj != req.From {
				bound = append(bound, proj)
			}
		}
		return nil, fmt.Errorf("relay: project %q is not bound in this chat. Available targets: %s (use the exact name)", req.To, strings.Join(bound, ", "))
	}
	if targetEngine == nil {
		return nil, fmt.Errorf("relay: target engine %q not found (is the project running?)", req.To)
	}

	fromName := req.From
	if binding.Bots[req.From] != "" {
		fromName = binding.Bots[req.From]
	}
	toName := req.To
	if binding.Bots[req.To] != "" {
		toName = binding.Bots[req.To]
	}

	// Post the forwarded message to the group chat for visibility.  The
	// default target is "<platform>:<chatID>:relay"; platforms that
	// understand thread / topic semantics can override this by
	// implementing core.RelayGroupVisibilityTarget on their Platform impl.
	groupSessionKey := rm.resolveGroupVisibilityKey(platform, chatID, req.SessionKey, sourceEngine)
	if sourceEngine != nil && visibility != RelayVisibilityNone {
		label := relayVisibilityRequestLabel(visibility, fromName, toName, req.Message)

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Start the target project's cc-connect instance/engine so it registers with the RelayManager
  2. Confirm the engine registration name exactly equals the bound project name
  3. Check the target process's logs for startup failure and fix the underlying cause
  4. After restarting, re-issue the relay request

Example fix

// before: engine never started
rm.RegisterEngine("backend", nil) // or never called
rm.Send(ctx, core.RelayRequest{To: "backend", ...}) // -> not found
// after: create and start the engine, then register
eng := core.NewEngine(cfg); go eng.Start(ctx); rm.RegisterEngine("backend", eng)
Defensive patterns

Strategy: validation

Validate before calling

func targetRunning(rm *core.RelayManager, name string) bool {
	rm.RLock(); defer rm.RUnlock()
	return rm.Engines()[name] != nil
}
// check before Send; if false, tell the user to start the target project

Type guard

if eng := rm.LookupEngine(req.To); eng == nil { return fmt.Errorf("project %s is not running", req.To) }

Try / catch

resp, err := rm.Send(ctx, req)
if err != nil {
	if strings.Contains(err.Error(), "target engine") && strings.Contains(err.Error(), "not found") {
		reply("Target project is not running. Start it and retry.")
		return
	}
	return err
}

Prevention

When it happens

Trigger: The target project's cc-connect process is stopped or crashed; the engine was never started/registered under the exact name used in the binding; a typo in the project's config name means the engine registered under a different key than the one bound.

Common situations: Second project not started yet (single cc-connect instance instead of per-project daemons); target engine crashed and wasn't restarted; project renamed in one place (config or /bind) but not the other.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/b23298c30ad5a30a. Report an issue: GitHub.