Skip to content

Backend configuration

An operator configures one deployment. The backend publishes part of that configuration to every client and keeps the rest private. This spec owns that boundary, the public configuration wire format, and how a client fetches, stores, binds to, and applies it. A client sizes its requests to the published values, not to compiled constants, and a client database is bound to exactly one deployment by the identifier the operator chooses.

In scope: the configuration checks the backend makes before it serves; the boundary between what is published and what stays private; the public configuration wire format; how a client fetches, validates, stores, and binds to it; what a refresh may change; the conditions under which a client stops; what a client sizes or rejects using it; and what an SDK exposes to an app.

Out of scope: the backend’s configuration file and its keys; credentials and authorization (AUTH); the backend API’s enforcement of limits and its errors (API section 7); operations such as retention, readiness, and telemetry (OPS); and the platform a deployment runs on.

RelatedRelation
AUTHOwns what a credential is, when a client attaches one, and which failures are terminal. This spec owns only what is published about it.
API section 7Owns what the backend does when a request exceeds a limit, and the fixed transport ceiling. This spec owns the published values and what a client does before it sends.
OPSOwns retention enforcement, health, and the identifier’s use in telemetry.
IDENTOwns handles: the grammar and the rules for a claim in an identity log. This spec owns only the published minimum name length.
EVENTEVENT-016 keeps local event subscriptions open after a server rejection. EVENT-001 owns the client.rejected_by_server event.
TermMeaning
DeploymentOne backend an operator runs, with one configuration and one identifier.
Deployment identifierThe value of GetConfigurationResponse.identifier: the name an operator gives a deployment. A client database is bound to exactly one.
Backend URLThe address a client is configured to reach a deployment at.
Stored copyThe GetConfigurationResponse a client keeps in its database, with the backend URL it was fetched from and any conflicting identifier recorded under CONF-030.
SnapshotThe configuration a client resolves when it is created and reads for its life.
Compiled defaultThe value in the defaults table of section 3 that a client uses for a field its snapshot does not carry.
Advisory valueA published value the backend does not enforce, because only a client holds the state it is about.
Blocked connectionA condition that, once observed, fails later network work for the life of the client.
RefreshA fetch of GetConfiguration by a client that already holds a snapshot, on its own schedule or when the app asks.
Credential sourceThe callback or key an app gives a client so that it can obtain credentials. AUTH section 6 defines the credential.

The backend validates its configuration before it serves. The checks below are the ones a client or an operator relies on: a published value a client would reject, or one the transport cannot honour. The ranges of other keys are documentation of the backend. A key the operator did not set takes the default in section 3.

IDTitleRequirementWhy
CONF-002Identifier is requiredWhen the configured deployment identifier is absent, empty, longer than 256 bytes, or contains a whitespace or control character, the backend MUST refuse to start.
CONF-003Stable identifierAn operator SHOULD NOT change a deployment identifier once a client has connected.Every client database that reached this deployment is bound to the old value, and CONF-030 stops each of them permanently.
CONF-067Minimum version is a semantic versionWhen the configured minimum client version is set and is not a version under Semantic Versioning 2.0.0 §2, the backend MUST refuse to start.A client rejects an answer whose minimum does not parse (CONF-071), so a deployment that starts with one is unusable by every client.
CONF-005Explicit credential intentWhen the configuration contains an [auth] table without an enabled key, the backend MUST refuse to start.A configuration that gained the table before the key existed would otherwise serve without credentials, on the strength of an omission.
CONF-066Disabled auth table is not validatedWhile the [auth] table has enabled set to false, the backend MUST start without validating the other keys of that table and MUST NOT fetch a key set.
CONF-008Request budgets fit the transportWhen the configured max_request_bytes or max_response_bytes is greater than the transport ceiling API-282 states, the backend MUST refuse to start.A larger budget publishes a request size the transport refuses to carry, so a client sized to it fails every large request.
CONF-009Public configuration stays smallWhen the encoded GetConfigurationResponse the backend would publish is longer than 65536 bytes (64 KiB), the backend MUST refuse to start.The message is served without a credential, so an unbounded one is an amplification source. Bounding the whole message bounds every list in it without a limit per list.
CONF-078Valid application catalogueWhen an operator configures an application component, the backend MUST refuse to start unless its component_id is in 0xC000–0xFEFF, its name contains 1 to 100 UTF-8 bytes, its component_type is one of the seven types in META section 2, all three member policies are present, and at least one of in_groups and in_dms is true; it MUST refuse duplicate IDs or names and a name equal to a well-known component name in META section 2.An unusable or ambiguous definition would be published to every client, and a duplicate name makes name lookup ambiguous.
CONF-080Handle name minimum in rangeWhen the configured handles.min_name_length is less than 1 or greater than 27, the backend MUST refuse to start.A client reads a published 0 as not provided (CONF-025), so an app would check names against the compiled default instead. Above 27, every claim fails, because no name part is longer than 27 characters.
CONF-065Refusal names the keyWhen the backend refuses to start under a rule in this section, it MUST report the configuration key that failed, or that the public configuration is too large.

Application component definitions are a sending catalogue: a client copies them into the registry of a conversation it creates or refreshes, and the committed group registry, not the catalogue, governs every received change. CONF-009 applies to the response including the catalogue. Operator documentation states that a published definition’s ID, name, type, policies, and conversation selection should stay stable, because a change reaches only conversations that register the ID later; no receive-side rule depends on that advice.

API-282 states the transport ceiling and the failure rule for a message above the ceiling or byte budget. API-281 owns the status codes.

A handle is a public name, such as nick or nick#2341, that an inbox claims in its identity log. handles.min_name_length is the shortest name part the backend admits in a claim. IDENT-078 states the handle grammar, whose name part is 1 to 27 characters, and IDENT-084 forbids a validator to check a claim’s name part against this setting when it validates an identity log. API-297 makes the backend fail a publish with REASON_HANDLE_NOT_ALLOWED when a claim in it has a name part shorter than this setting. A change of the setting applies only to later claims. A handle claimed before the change stays valid.

The backend publishes the values a client or an app acts on, on a request that needs no credential, and nothing else. Connection strings, key material, the JWKS URL, API key values, and credential-verification timing stay private. Of the auth configuration, a client acts on enabled and required_scopes; the key identities, audiences, and issuers are published for inspection. AUTH-001 through AUTH-003 own credential admission; AUTH section 3 defines the audience, issuer, and scope checks.

The message is built once at startup from the validated configuration and the key set loaded then. A key set refreshed while the process runs is not republished. An operator changes what is published by restarting.

This is the public configuration wire format. An absent scalar reads as 0 or empty, which a client treats as not provided under CONF-025; commit_log_enabled carries explicit presence because absent and false mean different things.

message GetConfigurationRequest {}
// Admission settings a client needs before it holds a credential. Never
// includes a JWKS URL, key material, leeway, or refresh timing.
message AuthConfiguration {
// Public identity of one accepted signing key. Never the key itself.
message SigningKey {
string kid = 1;
string alg = 2;
}
bool enabled = 1;
repeated SigningKey keys = 2;
repeated string audiences = 3;
repeated string issuers = 4;
repeated string required_scopes = 5;
}
message RetentionConfiguration {
uint64 group_message_seconds = 1;
uint64 welcome_seconds = 2;
uint64 key_package_seconds = 3;
}
// Request shapes the backend accepts. A client chunks its work to these values.
message LimitsConfiguration {
uint64 max_envelope_bytes = 1;
uint64 max_request_bytes = 2;
uint64 max_response_bytes = 3;
uint32 max_publish_topics = 4;
uint32 max_query_topics = 5;
uint32 max_query_limit = 6;
uint32 default_query_limit = 7;
uint32 max_newest_metadata_topics = 8;
uint32 max_newest_full_topics = 9;
uint32 max_update_adds = 10;
uint32 max_update_removes = 11;
uint32 max_stream_topics = 12;
uint32 max_static_topics = 13;
uint32 max_lookup_identifiers = 14;
uint32 max_scw_signatures = 15;
uint32 max_identity_entries = 16;
uint32 max_update_frames_per_second = 17;
uint32 max_update_burst = 18;
uint32 max_ping_frames_per_second = 19;
uint32 max_ping_burst = 20;
}
// Advisory group shapes. The backend does not enforce these values.
message MlsConfiguration {
uint32 max_group_members = 1;
uint32 max_installations_per_inbox = 2;
// Absent means the client keeps its compiled default.
optional bool commit_log_enabled = 3;
}
// Handle settings.
message HandlesConfiguration {
// The shortest name part, the text before "#", the backend admits in a claim.
uint32 min_name_length = 1;
}
// One operator-defined application component. A client registers it in the
// conversations the flags select; it carries no initial value.
message ApplicationComponentDefinition {
uint32 component_id = 1;
string name = 2;
xmtp.mls.message_contents.ComponentType component_type = 3;
xmtp.mls.message_contents.ComponentPermissions permissions = 4;
bool in_groups = 5;
bool in_dms = 6;
}
message GetConfigurationResponse {
// Stable operator-chosen name for this deployment. Never changes once
// clients have connected.
string identifier = 1;
string server_version = 2;
// Empty when the operator published no minimum.
string min_libxmtp_version = 3;
AuthConfiguration auth = 4;
RetentionConfiguration retention = 5;
LimitsConfiguration limits = 6;
MlsConfiguration mls = 7;
// CAIP-2 chain ids this backend verifies smart contract wallet signatures on.
repeated string smart_contract_wallet_chains = 8;
// Attachment storage this deployment offers; absent when it offers none.
// The message and its rules are owned by ATCH section 1.
xmtp.backend.v1.AttachmentsConfiguration attachments = 9;
// Sorted by component_id ascending.
repeated ApplicationComponentDefinition application_components = 10;
// Set on every deployment.
HandlesConfiguration handles = 11;
}
IDTitleRequirementWhy
CONF-017Public configuration wire formatThe backend MUST answer GetConfiguration with the GetConfigurationResponse defined above, with the field numbers and types shown, and MUST NOT reuse a field number of any message above for another meaning.
CONF-010Published without a credentialThe backend MUST answer GetConfiguration for a request that carries no credential, whatever the configured auth.enabled.A client cannot learn that credentials are required if learning it requires one.
CONF-079Publish application catalogueWhen the backend answers GetConfiguration, it MUST set application_components to every configured application component under the wire block in section 2.1, sorted by component_id ascending.Clients need a stable public view of the operator’s field definitions.
CONF-011Nothing secret is publishedThe backend MUST NOT place in any field of GetConfigurationResponse a signing key’s key material, a JWKS URL, a database URL, a chain RPC URL, or an API key value.The message has no access control, so the only protection a value has is not being in it.
CONF-012Stable for a processWhile a backend process is running, it MUST answer every GetConfiguration with the same GetConfigurationResponse.
CONF-069Published values are the applied valuesThe backend MUST set every field of LimitsConfiguration, RetentionConfiguration, and HandlesConfiguration to the value it enforces or applies for that key, every field of MlsConfiguration to the configured value, and min_libxmtp_version to the configured minimum or to the empty string when none is configured. It MUST set retention, limits, mls, and handles, and MUST NOT set a numeric field of those four messages to 0.A client reads 0 as “not provided” (CONF-025), so a 0 for a value the backend enforces tells the client to use a different one.
CONF-068Auth summary equals enforcementThe backend MUST set AuthConfiguration.enabled to the configured auth.enabled. While that is true, it MUST set keys to the kid and alg of each signing key accepted at startup and audiences, issuers, and required_scopes to the values it checks credentials against; while it is false, it MUST leave every other field of AuthConfiguration empty.Leftover scopes from a disabled table would tell a client to satisfy demands nothing checks.
CONF-070Published chains are the verifiable setThe backend MUST set smart_contract_wallet_chains to the CAIP-2 identifier of every chain it verifies smart contract wallet signatures on, and to no other.

A client resolves its snapshot once, when it is created, and reads it for its life. The client configures itself from the values it receives from the server. A changed value takes effect for a client created afterwards.

Two conditions block a client’s connection: a different deployment answering, and a raised minimum version. The blocked connection lasts for the life of the client. It fails operations that would reach the backend and closes streams that hold network interest with its error. Local event subscriptions stay open under EVENT-016. Which cause the client reports when both arise is the implementation’s choice. PROC-002 owns durable receipt and PROC-005 owns processed positions. Closing a stream can leave received work above the processed position; it does not erase that work.

A field the snapshot does not carry, or carries as 0 or empty, takes the compiled default below, which is the value the backend defaults the same key to.

FieldDefault value
min_libxmtp_versionNo minimum: every client version is accepted
authenabled false, every list empty
retention.group_message_seconds7776000
retention.welcome_seconds7776000
retention.key_package_seconds7776000
limits.max_envelope_bytes1048576
limits.max_request_bytes26214400
limits.max_response_bytes26214400
limits.max_publish_topics1000
limits.max_query_topics1000
limits.max_query_limit1000
limits.default_query_limit100
limits.max_newest_metadata_topics1000
limits.max_newest_full_topics100
limits.max_update_adds100000
limits.max_update_removes100000
limits.max_stream_topics100000
limits.max_static_topics10000
limits.max_lookup_identifiers250
limits.max_scw_signatures100
limits.max_identity_entries256
limits.max_update_frames_per_second10
limits.max_update_burst100
limits.max_ping_frames_per_second10
limits.max_ping_burst100
mls.max_group_members250
mls.max_installations_per_inbox10
mls.commit_log_enabled (absent)true
handles.min_name_length3
smart_contract_wallet_chains (empty)No chain: every app-supplied smart contract wallet signature is rejected under CONF-046
attachments (absent)No attachment storage: creation fails under ATCH-030
attachments.max_upload_bytes104857600
attachments.retention_secondsNo expiry

identifier has no default: an empty one is rejected under CONF-071. A present commit_log_enabled of false is not a missing value; it switches the commit log off under CONF-045.

IDTitleRequirementWhy
CONF-020One snapshot per clientThe client MUST NOT replace its snapshot after it is created, whatever a later fetch returns.
CONF-025Absent means the compiled defaultWhen a field of a snapshot is 0, empty, or absent, the client MUST use the value the table above gives for that field.
CONF-075Blocked connection stops network workWhile the client has a blocked connection, every operation that would publish an envelope, publish or apply an identity update, or sync a group MUST fail with the blocked connection’s error before any request is sent, and every open stream that holds network interest MUST close with that error.The client has lost its binding or been refused by the deployment. Network work against that deployment cannot succeed.

A client fetches the public configuration once, stores it with the backend URL, and reads the stored copy on every later creation. A stored copy that does not decode reads as the compiled defaults, with its identifier kept for CONF-030.

The identifier binds the database to a deployment. The URL does not, because an operator moves a deployment to a new address; a changed URL only triggers a re-check (CONF-033). A stored copy whose identifier is empty binds nothing.

A client validates an answer before it stores it (CONF-071). A uint64 above 2^53 - 1 is rejected because the JavaScript number cannot hold it exactly.

A client does not require the application catalogue sorted, and accepts a component_type or policy value it does not know and a name equal to a well-known component name, all of which the backend refuses (CONF-078, CONF-079). A newer deployment may publish any of them, and the committed group registry, not the catalogue, governs what a conversation accepts.

An app may create a client that does no network work (CONF-034). A client told to reach the deployment that cannot fails under CONF-027 and does not fall back to working offline.

IDTitleRequirementWhy
CONF-026Fetch before other workWhen a client that may reach the backend is created on a database with no stored copy, the client MUST send GetConfiguration, apply CONF-071 and CONF-030 to the answer, and store the answer with the backend URL, before it sends any other request.Identity work is sized by the limits and bound by the identifier. Run first, it can register an installation on the wrong deployment.
CONF-027Failed first fetchIf the fetch under CONF-026 or CONF-033 fails, or its answer cannot be stored, then the client MUST fail creation and MUST NOT use the compiled defaults in place of the answer.Compiled defaults would bind the database to nothing and size every request to values this deployment never published.
CONF-071Reject an unusable answerIf a GetConfigurationResponse carries an identifier that CONF-002 would refuse, a non-empty min_libxmtp_version that is not a version under Semantic Versioning 2.0.0 §2, a smart_contract_wallet_chains entry that does not match the syntax of CAIP-2, a uint64 or uint32 field of retention, limits, or mls greater than 9007199254740991, or an application_components entry whose component_id is outside 0xC000–0xFEFF, whose name is not 1 to 100 UTF-8 bytes, whose component_type is not positive, whose member policy is absent, unspecified, or an empty condition at any depth, whose in_groups and in_dms are both false, or whose component_id or name repeats an earlier entry’s, then the client MUST reject it and MUST NOT store it.
CONF-029Fetch carries no credentialWhen the client sends GetConfiguration, it MUST NOT attach a credential and MUST NOT invoke the app’s credential source.
CONF-030Identifier binds the databaseWhen a GetConfigurationResponse carries an identifier that differs from the stored copy’s non-empty identifier, the client MUST record the received identifier as a conflict in the stored copy, MUST block the connection with a backend mismatch naming both identifiers whether or not the record succeeded, and MUST NOT store the answer.Stored positions, group state, and identity state are meaningful only against the deployment that issued them.
CONF-072A recorded conflict fails creationWhen a client is created on a database whose stored copy records a conflict, the client MUST fail creation with a backend mismatch naming the stored and the conflicting identifier, without sending any request.
CONF-031A conflict is permanentThe client MUST NOT clear a recorded conflict, including when a later answer’s identifier equals the stored one.A database that has seen two deployments cannot be shown to hold consistent state for either. Only a database created for the deployment in use can.
CONF-033A moved deployment is re-checkedWhen a client that may reach the backend is created on a database whose stored copy carries a backend URL that differs from the client’s backend URL, the client MUST send GetConfiguration, apply CONF-071 and CONF-030, and store the answer with the new URL, before it sends any other request.
CONF-034Offline creationWhere an app creates a client that may not reach the backend, the client MUST use the stored copy when the database has one and the compiled defaults when it does not, and MUST NOT send GetConfiguration.
CONF-076Offline creation ignores a moved URLWhere an app creates a client that may not reach the backend, the client MUST NOT fail creation because the stored copy’s backend URL differs from the client’s backend URL.An app that moved its backend URL must still open offline; CONF-077 re-checks before the first request.
CONF-077Offline URL re-check before first requestWhen a client created under CONF-034 on a database whose stored copy carries a backend URL that differs from the client’s backend URL is about to send its first request after creation, it MUST send GetConfiguration, apply CONF-071 and CONF-030, and store the answer with the new URL before it sends that request, and MUST fail that request when this does not complete.Otherwise a database for one deployment sends its identity and group traffic to another deployment before any identifier check.

A refresh rewrites the stored copy and never the running snapshot (CONF-020). It can stop a live client in the two cases of section 3; everything else it learns takes effect when a client is next created on that database.

The client refreshes on its own schedule, spread at random. The interval, the spread, and the number of attempts in one run are the implementation’s choice. A refresh is never driven by a failed request, and a failed refresh leaves the stored copy unchanged.

IDTitleRequirementWhy
CONF-040Refreshes are persistedWhen a refresh returns an answer that passes CONF-071 and whose identifier equals the stored copy’s, the client MUST replace the stored copy with that answer.
CONF-036A raised minimumWhen a refresh returns a min_libxmtp_version that is greater than the client’s version under CONF-050, the client MUST store the answer and MUST block the connection because the client is too old, naming both versions.
CONF-037A failed refresh changes nothingIf a refresh does not return an answer that passes CONF-071, then the client MUST keep the stored copy unchanged and MUST NOT fail any other operation because of it.

The client splits and bounds its requests to the published limits, so that a request the backend would reject is never sent. The table below names the bound for each request. The fields it does not name (max_response_bytes, max_stream_topics, max_identity_entries, and the four rate-limit fields) are published for an app to read. API-281 and API-282 own response and request bounds, API-234 owns the identity-log limit, and API-258 owns stream frame rate limits.

RequestBound from the snapshot
PublishEncoded request not longer than max_request_bytes; distinct topics not more than max_publish_topics; each envelope not longer than max_envelope_bytes
QueryTopics per request not more than max_query_topics; limit not more than max_query_limit
QueryNewestTopics per request not more than max_newest_full_topics with full envelopes and max_newest_metadata_topics without
GetInboxIdsIdentifiers per request not more than max_lookup_identifiers
VerifySmartContractWalletSignaturesSignatures per request not more than max_scw_signatures
SubscribeStaticTopics per stream not more than max_static_topics
Subscribe updateadds not more than max_update_adds; removes not more than max_update_removes; encoded frame not longer than max_request_bytes

Group size and installation count are advisory: the backend has no view of the state they are about, so only a client can check them (Known limitations). GMOD section 2 owns group membership; IDENT section 8 defines the installations in an association state. FORK owns the commit log; this spec owns only the switch.

The chain check runs on a signature an app is about to produce. It does not run on a signature read from the network, which the network already accepted, or when the app supplied its own verifier. PROC-012 owns the preservation of unresolved work.

The version gate and the credential requirement fail creation, so an app gets one clear reason instead of every request failing.

handles.min_name_length is published for an app, which may check a name a user types against it before a claim. Only the backend applies it, when it admits a claim (section 1).

IDTitleRequirementWhy
CONF-073Size every request to the snapshotThe client MUST split or bound every request it sends so that it stays within each bound in the table above. When one envelope alone is longer than max_envelope_bytes, the client MUST reject the publish before it sends any request.
CONF-043Advisory group sizeWhen the number of distinct inboxes in a group’s GROUP_MEMBERSHIP component plus the inboxes a change would add is greater than max_group_members, the client MUST reject the change before it builds a commit.
CONF-044Advisory installation countWhen the number of installations an inbox’s association state names is not less than max_installations_per_inbox, the client MUST NOT register a new installation for that inbox.
CONF-045Commit log follows the deploymentWhile the snapshot’s commit_log_enabled is false, the client MUST NOT publish a commit-log entry and MUST NOT read the commit log.A deployment that keeps no commit log would be sent entries it discards, and clients would read an always-empty log as evidence about groups.
CONF-046Only published chains are acceptedWhen an app that supplied no verifier of its own supplies a smart contract wallet signature whose CAIP-2 chain id is not in smart_contract_wallet_chains, the client MUST reject it before it sends any request, naming the chain and the accepted chains.
CONF-048Chains and received dataThe client MUST NOT apply CONF-046 to a signature it reads from a received identity update or envelope.A signature the network already accepted is a fact. Refusing it would hold the client on that envelope for ever.
CONF-049Too old to runWhen the snapshot’s min_libxmtp_version is greater than the client’s version under CONF-050, the client MUST fail creation, naming both versions.
CONF-050Version compare ignores prereleaseWhen the client compares its version with a min_libxmtp_version, it MUST compare the major, minor, and patch numbers in that order (Semantic Versioning 2.0.0 §11) and MUST ignore the pre-release and build metadata of both.A prerelease build of the version the operator named would otherwise be too old, which stops every development build.
CONF-051Credentials required but absentWhen the snapshot’s AuthConfiguration.enabled is true and the app supplied no credential source, the client MUST fail creation and MUST report required_scopes.
CONF-081Client never applies name minimumThe client and an SDK MUST NOT fail an operation, and MUST NOT omit a handle from a result they return to an app, because a handle’s name part is shorter than the snapshot’s handles.min_name_length.A snapshot can be older than the deployment’s setting (CONF-020), and a raised minimum leaves the shorter handles claimed before it valid. A client that applied it would refuse a claim the backend admits, and hide a handle that other clients show.

AUTH-020 owns when the client attaches a credential, including when enabled is false and the app supplied a source.

An app needs the public configuration before a client exists, to choose credentials, scopes, and chains, so it is readable from a backend URL alone. After that it reads the snapshot the client holds, which under CONF-020 can differ from what the deployment publishes now.

IDTitleRequirementWhy
CONF-061Apps read the snapshotAn SDK MUST expose to an app the snapshot the client holds, with every field of GetConfigurationResponse.
CONF-062Reading before buildingAn SDK MUST let an app fetch a deployment’s GetConfigurationResponse from a backend URL alone, with no database, no client, and no credential, and MUST apply CONF-071 to the answer.
CONF-074Explicit refreshAn SDK MUST let an app start a refresh, and that refresh MUST apply CONF-071, CONF-030, CONF-036, and CONF-040 and return the fetched configuration.
CONF-064Failures are distinguishableAn SDK MUST let an app distinguish, as distinct error kinds, an unreachable deployment or an unstorable answer (CONF-027), an invalid answer (CONF-071), a backend mismatch (CONF-030, CONF-072), a client that is too old (CONF-049, CONF-036), a missing credential source (CONF-051), and a chain that is not accepted (CONF-046).

An advisory value binds only a client that applies it. A modified client can exceed the published group size or installation count, and the deployment will not notice. These values are a deployment’s policy for cooperating clients, not a protection against a hostile one.

The backend does not read a client’s version on a request. min_libxmtp_version is applied by the client alone, at creation and at refresh, so a client that never refreshes keeps working against a deployment that has raised its minimum.

A deployment behind one address may be more than one process, and two of them may hold different configurations during a rolling change. A client holds whichever it fetched. A limit lowered on one of them is still enforced by that one, so the client’s request is rejected rather than silently accepted; a differing identifier across processes is an operator error and stops every client that reaches the odd one.

An operator’s change reaches an existing client’s stored copy within one refresh interval and its behaviour only when a client is next created. If every refresh fails there is no upper bound on how stale a stored copy may be; the client keeps using it rather than falling back to the compiled defaults.

An app that checks a name against the snapshot’s handles.min_name_length uses the value from when the client was created (CONF-020). After the operator changes the setting, such an app can refuse a name the backend admits, or pass a name the backend refuses. The backend’s answer to the claim decides.

Anyone who can reach the backend API can read the public configuration, including the auth summary and the accepted chains (CONF-010). CONF-011 keeps it harmless to disclose.

GetConfiguration is not rate limited.