block / block/buzz

Link preview rejects messages with bare-domain URLs due to trailing-slash normalization mismatch

Open
#6,347 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
32.7k
Forks
4.3k
Avg merge
1d 13h
Merged PRs (30d)
253

Description

**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**
1. 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
```
2. Click Send
3. 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:
```json
{"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:
```javascript
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:**

1. **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.

2. **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.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.