Describe the bug
Messages containing a bare-domain HTTPS URL (e.g., https://api.airtable.com) fail to send with invalid link-preview canonical URL. Desktop normalizes the URL by adding a trailing slash (https://api.airtable.com/), but the relay's validation requires the canonical URL to appear verbatim in the message body.
Steps to reproduce
- In Desktop, compose a message containing a bare-domain URL without a trailing slash, e.g.:
Request failed for https://api.airtable.com returned code 403
- Click Send
- The button returns to its default state without sending; relay log shows
status=400 reason="invalid: invalid link-preview canonical URL"
Expected behavior
The message should send. Either Desktop should preserve the original URL form (without normalizing), or the relay should normalize both sides before comparing.
Version and platform
- Buzz version: 0.5.14
- OS: macOS 26.5.2 (Apple Silicon)
Logs / additional context
Relay log:
{"timestamp":"2026-08-19T16:03:53.232211Z","level":"WARN","message":"HTTP bridge request","status":400,"accepted":false,"kind":9,"reason":"invalid: invalid link-preview canonical URL"}
Root cause:
JavaScript's URL class adds a trailing slash when normalizing bare-domain URLs:
new URL('https://api.airtable.com').href
// => "https://api.airtable.com/"
Desktop's linkPreview.ts:287 uses canonical.href (the normalized form) in the snapshot tag.
The relay's ingest.rs:259 then checks !event.content.contains(&parts[3]), which fails because the message body contains https://api.airtable.com but the tag contains https://api.airtable.com/.
Suggested fix options:
-
Desktop-side: In createPreview(), preserve the original detected URL string for the canonical URL instead of round-tripping through new URL().href. The fragment-stripping can be done with string manipulation instead.
-
Relay-side: Normalize the canonical URL before the contains check (strip trailing slash from root paths), or compare after URL parsing both sides.
Option 1 is probably cleaner since it makes Desktop's output match what the user typed.
Describe the bug
Messages containing a bare-domain HTTPS URL (e.g.,
https://api.airtable.com) fail to send withinvalid link-preview canonical URL. Desktop normalizes the URL by adding a trailing slash (https://api.airtable.com/), but the relay's validation requires the canonical URL to appear verbatim in the message body.Steps to reproduce
status=400 reason="invalid: invalid link-preview canonical URL"Expected behavior
The message should send. Either Desktop should preserve the original URL form (without normalizing), or the relay should normalize both sides before comparing.
Version and platform
Logs / additional context
Relay log:
{"timestamp":"2026-08-19T16:03:53.232211Z","level":"WARN","message":"HTTP bridge request","status":400,"accepted":false,"kind":9,"reason":"invalid: invalid link-preview canonical URL"}Root cause:
JavaScript's
URLclass adds a trailing slash when normalizing bare-domain URLs:Desktop's
linkPreview.ts:287usescanonical.href(the normalized form) in the snapshot tag.The relay's
ingest.rs:259then checks!event.content.contains(&parts[3]), which fails because the message body containshttps://api.airtable.combut the tag containshttps://api.airtable.com/.Suggested fix options:
Desktop-side: In
createPreview(), preserve the original detected URL string for the canonical URL instead of round-tripping throughnew URL().href. The fragment-stripping can be done with string manipulation instead.Relay-side: Normalize the canonical URL before the
containscheck (strip trailing slash from root paths), or compare after URL parsing both sides.Option 1 is probably cleaner since it makes Desktop's output match what the user typed.