Skip to content

Return 404 when fetching an unset displayname or avatar_url - #20174

Draft
barodeur wants to merge 3 commits into
element-hq:developfrom
barodeur:fix-missing-legacy-fields-error
Draft

Return 404 when fetching an unset displayname or avatar_url#20174
barodeur wants to merge 3 commits into
element-hq:developfrom
barodeur:fix-missing-legacy-fields-error

Conversation

@barodeur

@barodeur barodeur commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

⚠️ This change is not backward compatible. Not sure yet what's the best way to handle this.

GET /_matrix/client/v3/profile/{userId}/displayname (likewise avatar_url) returned 200 {"displayname": null} when the field is unset, where the spec documents a 404 for a profile key that does not exist. Custom fields on the same endpoint already 404 correctly, so built-in and custom keys behaved differently on the same route:

Before:

GET /_matrix/client/v3/profile/@alice:example.com/avatar_url   (no avatar set)
→ 200 {"avatar_url": null}

After:

GET /_matrix/client/v3/profile/@alice:example.com/avatar_url   (no avatar set)
→ 404 {"errcode": "M_NOT_FOUND", "error": "Profile was not found"}

This is not hypothetical: the 200-with-null shape already breaks spec-compliant clients — ruma's get_profile_field fails to deserialize {"avatar_url": null} (ruma/ruma#2360), affecting Element X, and matrix-rust-sdk carries workarounds for it (matrix-org/matrix-rust-sdk#6148, matrix-org/matrix-rust-sdk#6883).

Backward compatibility

⚠️ not sure how to handle this backward incompatible change. Checking matrix-rust-sdk at current main against this change:

Fixes #13137. Related: #19466 (this addresses the GET inconsistency reported there; the PUT-with-empty-string behaviour is out of scope).

Pull Request Checklist

  • Pull request is based on the develop branch
  • Pull request includes a changelog file. The entry should:
    • Be a short description of your change which makes sense to users. "Fixed a bug that prevented receiving messages from other servers." instead of "Moved X method from EventStore to EventWorkerStore.".
    • Use markdown where necessary, mostly for code blocks.
    • End with either a period (.) or an exclamation mark (!).
    • Start with a capital letter.
    • Feel free to credit yourself, by adding a sentence "Contributed by @github_username." or "Contributed by [Your Name]." to the end of the entry.
  • Code style is correct (run the linters)

Per the spec, GET /_matrix/client/v3/profile/{userId}/displayname (and
avatar_url) should return 404 when the field is unset, but Synapse
returns 200 with a null value. Custom fields on the same endpoint
already 404 correctly.

These tests currently fail; the fix lands in the next commit.
Per the spec, GET /_matrix/client/v3/profile/{userId}/{keyName} should
return 404 when the requested field is unset. Custom fields already
behaved this way, but displayname and avatar_url returned 200 with a
null value.

Raise the 404 in the servlet rather than in the profile handler's
get_displayname/get_avatar_url, since the SSO handler relies on those
returning None for unset fields, and the federation profile query
handler has its own semantics for missing fields.

Custom fields are unaffected: unlike displayname/avatar_url they can
legitimately hold a JSON null, which still returns 200.

Fixes element-hq/backend-internal#277.
See also element-hq#13137.
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.

GET /profile/<USER_ID>/avatar_url and /profile/<USER_ID>/displayname return 200 with for users lacking an displayname and avatar, contradicting the spec

1 participant