Skip to main content

Topic Administration

Rafka treats topics as first-class entities — not implicit names that spring into existence on first produce, but registered objects with an identity, a config store, and an explicit lifecycle. P2.A ships four Kafka admin API keys that expose this model to standard Kafka clients.

Topic identity model

Every registered topic carries three forms of identity:

FieldExamplePurpose
idtop_01ktb7wm5jvkbfgpzvfnk3kqqbStable globally-unique ULID-branded id. top_ prefix prevents cross-entity confusion.
slugmy-topicURL/routing-safe form. Derived by Slug::sanitize(name): lowercase, non-[a-z0-9-]-, consecutive - collapsed, leading/trailing - trimmed, clamped to 63 chars.
RRLrafka/prod/east/topics/my-topicRafka Resource Locator: <org>/<env>/<cluster>/topics/<slug>. Uniquely addresses the topic within the mesh.

The raw Kafka name is stored verbatim alongside the slug. Kafka's naming rules ([a-zA-Z0-9._-], ≤249 chars, not . or ..) apply; the slug is derived from the name and is not independently validated as a Kafka name.

Example: topic named My.Topic → slug my-topic → RRL rafka/prod/east/topics/my-topic.

RRLs contain slashes, not colons. They are never placed in a URL path segment. Pass as a query parameter (?rrl=...) or request body field ({"rrl": "..."}) when needed.

Auto-create semantics

Rafka distinguishes two topic-creation paths:

PathWhen it firesError code
AdminClient explicit createAdminClient.create_topics(...) → api_key 19Success: 0. Duplicate: 36.
Producer auto-createMetadata request with allow_auto_topic_creation=true (librdkafka producer default)Registers with 1 partition; no error.
AdminClient describeMetadata with allow_auto_topic_creation=false (AdminClient list/describe default)Topic absent → 3 UNKNOWN_TOPIC_OR_PARTITION.

The allow_auto_topic_creation flag is decoded from MetadataRequest (present at API version 4+). It is per-request, not a global config — the same gateway serves both producers (auto-create on) and AdminClients (auto-create off).

Produce operations are unaffected by the registry. Records are written to the WAL regardless of whether the topic is explicitly registered; the WAL materialises the virtual-topic key on first append.

Lifecycle operations

Create (api_key 19 — CreateTopics)

CreateTopics -> topic name, num_partitions, replication_factor, config map

Validations (Kafka-standard error codes):

  • Empty name / . / .. / chars outside [a-zA-Z0-9._-] / >249 chars → 17 INVALID_TOPIC_EXCEPTION
  • num_partitions < 137 INVALID_PARTITIONS
  • replication_factor < 138 INVALID_REPLICATION_FACTOR
  • cleanup.policy=compact with rafka.failover.enabled=true40 INVALID_CONFIG
  • Already registered → 36 TOPIC_ALREADY_EXISTS

On success: the topic entity is stored in the registry with the requested partition count, RF, and config map.

List (Metadata wildcard — api_key 3)

Metadata(topics=null, allow_auto_topic_creation=false) -> all registered topics

AdminClient.list_topics() sends a null topic list with allow_auto_topic_creation=false. Rafka returns all registered topics for the org, each with their partition count from the registry.

Describe partition count (Metadata named — api_key 3)

After create, a named Metadata request with allow_auto_topic_creation=false returns the topic's registered partition count. This is how list_topics() resolves the partition count — not from the CreateTopics response.

v4-cap note: CreateTopics is advertised at api_version 0–4. The num_partitions echo field in the response is only present at v5+ (flexible encoding). At v4, the field is absent and returns -1. This is benign: real AdminClients read the partition count from Metadata (see above), not from the create response. Verified by conformance test.

DescribeConfigs (api_key 32)

Returns all stored configs for a topic. config_source=1 (DYNAMIC_TOPIC_CONFIG). Absent topic → error_code=3. Config names filter from the request is currently ignored; all stored configs are returned.

AlterConfigs (api_key 33)

Full-replace semantics: the incoming config map entirely replaces the existing one. To add a key without removing others, include all desired keys in the request.

Config validations:

  • rafka.failover.enabled is set at CreateTopics time only (I2 immutability rule). Any AlterConfigs that changes the flag value — whether false→true or true→false — returns 40 INVALID_CONFIG. Set it in the config map of NewTopic if you need it enabled.
  • cleanup.policy containing compact while rafka.failover.enabled=true returns 40 INVALID_CONFIG (incompatible with Op 36 offset translation).

Delete (api_key 20 — DeleteTopics)

Removes the topic from the registry and purges all WAL state for its partitions via KAFKA_OP_DELETE_TOPIC (mesh-op 0x05). Absent topic → error_code=3. The WAL purge is best-effort (registry remove is authoritative; broker errors are logged but do not fail the response).

Error code reference

CodeNameWhen emitted
0Success
3UNKNOWN_TOPIC_OR_PARTITIONAbsent topic in Delete / DescribeConfigs / AlterConfigs / Metadata(flag=false)
17INVALID_TOPIC_EXCEPTIONName violates Kafka naming rules
36TOPIC_ALREADY_EXISTSCreateTopics duplicate name
37INVALID_PARTITIONSnum_partitions < 1
38INVALID_REPLICATION_FACTORreplication_factor < 1
40INVALID_CONFIGConfig combination conflict