nats-io/nats-server · error

duplicate call to create subscription for service import

Error message

duplicate call to create subscription for service import

What it means

Returned by addServiceImportSub when the serviceImport entry already has a subscription id (si.sid != nil), meaning a subscription for this service import was already created and the duplicate creation attempt is rejected to prevent double-delivery.

Source

Thrown at server/accounts.go:2268

	if c == nil {
		return nil, fmt.Errorf("no internal account client")
	}

	return c.processSubEx([]byte(subject), nil, []byte(sid), cb, false, false, ri)
}

// This will add an account subscription that matches the "from" from a service import entry.
func (a *Account) addServiceImportSub(si *serviceImport) error {
	a.mu.Lock()
	c := a.internalClient()
	// This will happen in parsing when the account has not been properly setup.
	if c == nil {
		a.mu.Unlock()
		return nil
	}
	if si.sid != nil {
		a.mu.Unlock()
		return fmt.Errorf("duplicate call to create subscription for service import")
	}
	a.isid++
	sid := strconv.FormatUint(a.isid, 10)
	si.sid = []byte(sid)
	subject := si.from
	a.mu.Unlock()

	cb := func(sub *subscription, c *client, acc *Account, subject, reply string, msg []byte) {
		c.pa.delivered = c.processServiceImport(si, acc, msg)
	}
	sub, err := c.processSubEx([]byte(subject), nil, []byte(sid), cb, true, true, false)
	if err != nil {
		return err
	}
	// Leafnodes introduce a new way to introduce messages into the system. Therefore forward import subscription
	// This is similar to what initLeafNodeSmapAndSendSubs does
	// TODO we need to consider performing this update as we get client subscriptions.
	//      This behavior would result in subscription propagation only where actually used.

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Do not call the internal subscribe helper twice for the same service import entry.
  2. Clear/recreate the service import entry if a fresh subscription is required.
  3. Check si.sid before requesting subscription creation.

Example fix

// before
acc.subscribeInternal(si, cb)
acc.subscribeInternal(si, cb) // duplicate
// after
if si.sid == nil {
    acc.subscribeInternal(si, cb)
}
Defensive patterns

Strategy: validation

Validate before calling

if si.sid != nil {
    return errors.New("service import already subscribed")
}

Try / catch

if err := setupServiceImportSubscription(acc, si, cb); err != nil {
    if strings.Contains(err.Error(), "duplicate call") {
        // skip; subscription already active
    }
}

Prevention

When it happens

Trigger: Invoking the internal subscription creation path twice for the same serviceImport entry, e.g. duplicate setup during import processing or re-registration without clearing sid.

Common situations: Race conditions or re-entrant account import updates processing the same import twice; manually calling internal setup helpers in tests.

Related errors


AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02). Data as JSON: /api/errors/7c12e19d22039729. Report an issue: GitHub.