Skip to content

Update metadata spec - #613

Open
skizzerz wants to merge 4 commits into
ircv3:masterfrom
skizzerz:metadata-updates
Open

Update metadata spec#613
skizzerz wants to merge 4 commits into
ircv3:masterfrom
skizzerz:metadata-updates

Conversation

@skizzerz

@skizzerz skizzerz commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

The errata section at the bottom lists all normative changes. Additionally, the specification was rearranged and copyedited to flow more nicely when read from top-to-bottom. It should (hopefully) be possible to now follow the specification without needing to jump around, and all concepts are (hopefully) introduced before being used in the specification. Some examples were moved inline to help illustrate, although the rather large examples section at the end was maintained in case it was helpful.

Addresses issues and discussion from #588

Summary of changes between earlier versions of this PR and the current version

  • The LIMIT_REACHED FAIL code has gained a new parameter to indicate the subcommand for which the limit was reached, allowing clients to statelessly track whether the limit was reached for SUB vs SET
  • The RATE_LIMITED FAIL code was removed and the ERR_METADATARATELIMIT error numeric (775) was reintroduced to indicate commands are rate-limited; this allows clients to retry the command without needing stateful tracking as the numeric can pass a useful trailing parameter while standard reply trailing parameters must be for human consumption
  • RPL_METADATASYNCLATER was renamed to ERR_METADATASYNCLATER; unlike the changes above this is not a breaking change but rather reflects that the command was not successfully executed

Summary of changes between draft/metadata-2 and this PR

Standard Replies

  • Standard reply codes have been adjusted to use WARN and NOTE when and where appropriate. FAIL is reserved for when the entire command cannot proceed due to an error. WARN is used when a portion of a command cannot proceed but other parts may still proceed. NOTE is used when a portion of a command is fully successful but needs ancillary data.
  • The SUBCOMMAND_INVALID standard reply code has been removed. The more generic INVALID_PARAMS code should be used in its place.
  • The KEY_NOT_SET standard reply code has been removed. With its removal, METADATA SET is fully idempotent with regards to its replies.
  • The TOO_MANY_SUBS standard reply code has been removed. The LIMIT_REACHED standard reply code should be used in its place.
  • The VALUE_INVALID standard reply code has been renamed to INVALID_VALUE for better consistency between this specification and other specifications. It additionally now takes a <Key> parameter.
  • The KEY_INVALID standard reply code has been renamed to INVALID_KEY for better consistency between this specification and other specifications.
  • The RATE_LIMITED standard reply code is now specified for every subcommand. (now removed)
  • The INVALID_PARAMS standard reply code has been added for all other errors with METADATA command parameters.

Server Messages / Numerics

  • The METADATA server message was removed; 761 RPL_KEYVALUE and 766 RPL_KEYNOTSET are used in all cases to advertise key values or the lack thereof.
  • Servers sending either a metadata batch or 774 RPL_METADATASYNCLATER upon JOIN, 730 RPL_MONONLINE, or when a client subscribes to a new key post-registration is no longer optional.
  • The <RetryAfter> parameter of 774 RPL_METADATASYNCLATER and RATE_LIMITED is no longer optional and must be a non-negative integer.

CAP changes

  • The CAP token is now draft/metadata-3.
  • Clients removing either the metadata or batch CAPs from themselves are now automatically unsubscribed from all keys.
  • A max-key-bytes token was added to the CAP value to limit the maximum number of bytes a metadata key may consume.
  • The before-connect token in the CAP value list was clarified to not have its own value and that clients must ignore any value it carries.
  • CAP value tokens which specify maximum lengths or numbers of entries (i.e. max-key-bytes, max-value-bytes, max-keys, and max-subs) are clarified to be unlimited if those tokens are missing from the CAP LS 302 response.

Other

  • The *ALL target has been specified for METADATA SYNC to synchronize all visible targets.
  • Empty strings are no longer valid metadata values; setting a metadata key to an empty string will now remove it (in addition to removal by omitting the value parameter entirely).

The errata section at the bottom lists all normative changes.
Additionally, the specification was rearranged and copyedited to flow
more nicely when read from top-to-bottom. It should (hopefully) be
possible to now follow the specification without needing to jump around,
and all concepts are (hopefully) introduced before being used in the
specification. Some examples were moved inline to help illustrate,
although the rather large examples section at the end was maintained in
case it was helpful.
Comment thread extensions/metadata.md
Comment thread extensions/metadata.md Outdated
Comment thread extensions/metadata.md
- Move CAP to draft/metadata-3
- Add missing change entry that empty values are no longer permitted and
  are treated as unsetting the key in the Errata list (this was the case
  in the original version of this PR but was omitted from the Errata
  listing)
- Fix incorrect example citing a `SYNC` target of `*` instead of `*ALL`
- Further clarify which CAP tokens should be treated as unlimited if
  missing from CAP LS 302
Comment thread extensions/metadata.md
METADATA <Target> SET <Key> [:<Value>]

If the key is invalid, the server responsds with `FAIL METADATA KEY_INVALID` and fails the request.
This subcommand sets the key on the target to the given value. If the Value parameter is omitted or is an empty string, the key is removed. If the request is successful, the server carries out the requested change and responds with one `761 RPL_KEYVALUE` event, representing the new value if any, or `766 RPL_KEYNOTSET` if no value is set. This new value MAY differ from the one sent by the client.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get the case for disallowing the empty value, but then what's the case for accepting it here and treating it as a deletion, instead of rejecting it with a FAIL? It seems like a bit of a footgun.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I originally was going the other direction: making the value param mandatory instead of having the number of parameters vary based on set vs delete. I ended up keeping the syntax as-is for backwards compatibility because I didn't feel there was a strong enough reason to break it.

The advantage of allowing empty string = delete is that it makes it simpler client-side to delete a key. They can just "stupidly" append the key value to "METADATA foo SET key :" and it'll Just Work(tm). No need to detect deletion client-side and send it on the wire in any special format.

- The LIMIT_REACHED FAIL code has gained a new parameter to indicate the
  subcommand for which the limit was reached, allowing clients to
  statelessly track whether the limit was reached for SUB vs SET
- The RATE_LIMITED FAIL code was removed and the ERR_METADATARATELIMIT
  error numeric (775) was reintroduced to indicate commands are
  rate-limited; this allows clients to retry the command without needing
  stateful tracking as the numeric can pass a useful trailing parameter
  while standard reply trailing parameters must be for human consumption
- RPL_METADATASYNCLATER was renamed to ERR_METADATASYNCLATER; unlike the
  changes above this is not a breaking change but rather reflects that
  the command was not successfully executed
- Examples were updated to match the changes above
@jwheare

jwheare commented Jul 23, 2026

Copy link
Copy Markdown
Member

FAIL METADATA LIMIT_REACHED isn't documented in METADATA SET subcommand section.


I'm not going to block it but for the record, as mentioned in IRC, I would still prefer TOO_MANY_SUBS retained for SUB and LIMIT_REACHED dedicated for SET.

The overloaded meaning of the Item param and the need to include a Command param are API smells to me. It's also a bit of a headache to support both this and the previous version for compatibility, and that's somewhat expected for drafts, but seems unnecessary.

I understand the stylistic desire to abstract these two similar seeming error codes, but I disagree that this is an elegant solution.

Document LIMIT_REACHED for METADATA SET. Additionally, remove the note
about clients deduplicating SYNCLATER in the normative section on
postponed synchronization and instead add a paragraph to the
non-normative client implementation considerations that matches the
original intent of the note (doing a single METADATA *ALL SYNC after
automatic joins instead of individual channel syncs). Finally, rework
how inline examples are handled so it can render better on the ircv3.net
website.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants