{"record":{"id":"6e211d214898688c","repo":"t8y2/dbx","slug":"the-built-in-exchange-s-cannot-be-deleted","errorCode":null,"errorMessage":"The built-in exchange '%s' cannot be deleted","messagePattern":"The built-in exchange '(.+?)' cannot be deleted","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agents/drivers/rabbitmq/operations.go","lineNumber":487,"sourceCode":"\tif strings.TrimSpace(name) == \"\" {\n\t\treturn \"\", errors.New(\"name is required\")\n\t}\n\treturn name, nil\n}\n\nfunc validateExchangeType(exchangeType string) (string, error) {\n\tif _, ok := exchangeTypes[exchangeType]; !ok {\n\t\treturn \"\", fmt.Errorf(\"Invalid exchange type '%s'. Supported types: direct, fanout, topic, headers\", exchangeType)\n\t}\n\treturn exchangeType, nil\n}\n\nfunc assertExchangeDeletable(name string) error {\n\tif name == \"\" {\n\t\treturn errors.New(\"The default exchange cannot be deleted\")\n\t}\n\tif strings.HasPrefix(name, \"amq.\") {\n\t\treturn fmt.Errorf(\"The built-in exchange '%s' cannot be deleted\", name)\n\t}\n\treturn nil\n}\n\nfunc (s *server) listBindings(params jsonObject) (any, error) {\n\tconnection, err := s.requireConnectionConfig(params)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tallVhosts := allVhostsRequested(params)\n\tbindings, err := managementGetAll(connection, managementListPath(params, connection, \"bindings\"))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\texchangeFilter := stringOrEmpty(params, \"exchange\")\n\tqueueFilter := stringOrEmpty(params, \"queue\")\n\tresult := make([]jsonObject, 0, len(bindings))\n\tfor _, value := range bindings {","sourceCodeStart":469,"sourceCodeEnd":505,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/drivers/rabbitmq/operations.go#L469-L505","documentation":"Exchanges named 'amq.*' are built-in exchanges predeclared by RabbitMQ and are reserved/deletion-protected by the broker. The driver refuses to delete them (and the default '' exchange) client-side to avoid guaranteed broker failures.","triggerScenarios":"Calling deleteExchange with a name starting with 'amq.' (e.g. 'amq.direct', 'amq.topic') or the empty-string default exchange.","commonSituations":"Listing exchanges from the broker and blindly deleting every entry, including built-ins; cleanup scripts iterating all exchanges without filtering.","solutions":["Filter out 'amq.'-prefixed and empty-name exchanges from your delete list","Delete only application-created exchanges","Adjust discovery code to skip built-ins when enumerating exchanges"],"exampleFix":"// before\nfor (const e of exchanges) await client.deleteExchange({\"name\": e.name}) // includes amq.topic\n// after\nfor (const e of exchanges) {\n  if (e.name !== \"\" && !e.name.startsWith(\"amq.\")) await client.deleteExchange({\"name\": e.name})\n}","handlingStrategy":"validation","validationCode":"function deletableExchange(name) {\n  return typeof name === \"string\" && name !== \"\" && !name.startsWith(\"amq.\")\n}","typeGuard":"function isUserExchange(v) {\n  return typeof v === \"string\" && v.length > 0 && !v.startsWith(\"amq.\")\n}","tryCatchPattern":"try {\n  await client.deleteExchange({ name })\n} catch (e) {\n  if (String(e.message).includes(\"built-in exchange\")) {\n    console.warn(`skipping protected exchange ${name}`)\n  } else { throw e }\n}","preventionTips":["Filter 'amq.'-prefixed and empty names out of any bulk-delete list","Only delete exchanges your application created and recorded","Keep an allowlist of app-owned exchange names"],"tags":["rabbitmq","exchange","lifecycle","guard"],"backgroundTag":"protected-resource","analyzedSha":"c0390bff16418b651f4728520d99adf8ce48829a","analyzedAt":"2026-09-05T23:05:10.900Z","contentChangedAt":"2026-09-05T23:05:10.900Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}