t8y2/dbx · error

The default exchange cannot be deleted

Error message

The default exchange cannot be deleted

What it means

assertExchangeDeletable() implements a semantic guard in deleteExchange that refuses to delete the default exchange. The default exchange ("" empty string) is a built-in RabbitMQ construct that cannot and should not be removed, so the library blocks the operation up front. A second guard in the same function blocks 'amq.*' built-in exchanges with a different message.

Source

Thrown at agents/drivers/rabbitmq/operations.go:484

func exchangeName(params jsonObject) (string, error) {
	name := stringOrEmpty(params, "name")
	if strings.TrimSpace(name) == "" {
		return "", errors.New("name is required")
	}
	return name, nil
}

func validateExchangeType(exchangeType string) (string, error) {
	if _, ok := exchangeTypes[exchangeType]; !ok {
		return "", fmt.Errorf("Invalid exchange type '%s'. Supported types: direct, fanout, topic, headers", exchangeType)
	}
	return exchangeType, nil
}

func assertExchangeDeletable(name string) error {
	if name == "" {
		return errors.New("The default exchange cannot be deleted")
	}
	if strings.HasPrefix(name, "amq.") {
		return fmt.Errorf("The built-in exchange '%s' cannot be deleted", name)
	}
	return nil
}

func (s *server) listBindings(params jsonObject) (any, error) {
	connection, err := s.requireConnectionConfig(params)
	if err != nil {
		return nil, err
	}
	allVhosts := allVhostsRequested(params)
	bindings, err := managementGetAll(connection, managementListPath(params, connection, "bindings"))
	if err != nil {
		return nil, err
	}
	exchangeFilter := stringOrEmpty(params, "exchange")

View on GitHub (pinned to c0390bff16)

Solutions

  1. Remove the default exchange (empty name) from your deletion list — it is built-in and cannot be deleted.
  2. Filter out empty and 'amq.'-prefixed exchange names before calling deleteExchange.
  3. If the intent is to unbind a queue from the default exchange, call unbind instead of deleteExchange.

Example fix

// before
for _, name := range exchangeNames {
    deleteExchange(jsonObject{"name": name}) // fails on ""
}
// after
for _, name := range exchangeNames {
    if name == "" || strings.HasPrefix(name, "amq.") {
        continue
    }
    deleteExchange(jsonObject{"name": name})
}
Defensive patterns

Strategy: validation

Validate before calling

if name == "" || strings.HasPrefix(name, "amq.") {
    return errors.New("refusing to delete built-in exchange: " + name)
}
deleteExchange(jsonObject{"name": name})

Type guard

func isDeletableExchange(name string) bool {
    return name != "" && !strings.HasPrefix(name, "amq.")
}

Prevention

When it happens

Trigger: Calling deleteExchange with name set to "" (the empty string denotes the default exchange in AMQP). Note the guard checks name == "" exactly, so a whitespace-only name would NOT be caught here.

Common situations: Bulk cleanup scripts that iterate over a list of exchange names where one entry is empty; config where the exchange name defaults to "" when unset; attempting to 'reset' a vhost by deleting all exchanges including the implicit default one.

Related errors


AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05). Data as JSON: /api/errors/f8575c08f2a16b42. Report an issue: GitHub.