Skip to content

fix(schema): accept relative permalinks from self-hosted Sentry#1101

Closed
n8tron450 wants to merge 1 commit into
getsentry:mainfrom
n8tron450:fix/self-hosted-relative-permalink
Closed

fix(schema): accept relative permalinks from self-hosted Sentry#1101
n8tron450 wants to merge 1 commit into
getsentry:mainfrom
n8tron450:fix/self-hosted-relative-permalink

Conversation

@n8tron450

Copy link
Copy Markdown

Problem

IssueSchema.permalink is validated with z.string().url(). Self-hosted Sentry returns relative permalinks (e.g. /organizations/<org>/issues/<id>/) rather than absolute URLs, so validation throws Invalid url on the permalink path. This makes search_issues (and any tool returning issues) fail entirely against self-hosted instances (e.g. --host localhost:9000 --insecure-http).

Fix

Relax permalink to z.string(). The field is display-only and never parsed as a URL, so URL validation adds no value while breaking self-hosted users.

Testing

Verified against a self-hosted Sentry instance: search_issues returns results instead of erroring on permalink validation.

🤖 Generated with Claude Code

IssueSchema.permalink used z.string().url(), which rejects the relative
permalinks (e.g. "/organizations/<org>/issues/<id>/") that self-hosted
Sentry returns. This makes search_issues / get_issue fail with
"Invalid url" on self-hosted instances. permalink is display-only and
never parsed as a URL, so relax it to z.string().

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dcramer

dcramer commented Jun 17, 2026

Copy link
Copy Markdown
Member

Traced through the Sentry source to verify — the bug is real, but there are actually two mechanisms at play:

Path 1 — unconfigured system.url-prefix (likely for dev/testing setups)

  • Group.get_absolute_url()organization.absolute_url()absolute_uri(path, url_prefix=...)
  • absolute_uri falls back to options.get("system.url-prefix"), which defaults to os.environ.get("SENTRY_SYSTEM_URL_PREFIX")
  • if that env var isn't set, url_prefix is empty, and urljoin("/", "organizations/myorg/issues/123/") produces the literal relative path /organizations/myorg/issues/123/
  • this is where the "relative URL" claim in the PR description is accurate

Path 2 — system.url-prefix is set to http://localhost:9000

  • the result IS an absolute URL (http://localhost:9000/organizations/...)
  • but Zod v3's .url() validator uses a regex that requires a dotted hostname (e.g. sentry.io) — localhost fails validation
  • this is a known Zod footgun

The --host localhost:9000 --insecure-http test setup would hit Path 2 (or both).

Fix is sound: permalink is display-only — it's returned in the serialized output and never parsed as a URL in MCP. Relaxing to z.string() is the right call.

@dcramer

dcramer commented Jun 17, 2026

Copy link
Copy Markdown
Member

the above is one of our agents, but fwiw you need to configure the url prefix on a self hosted install or a bunch of other things will break (like outbound emails)

i think id rather let this break because otherwise we have all sorts of edge cases we have to handle here that should be handled upstream

@dcramer

dcramer commented Jun 17, 2026

Copy link
Copy Markdown
Member

going to close as a wontfix but happy to hear arguments otherwise

@dcramer dcramer closed this Jun 17, 2026
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.

2 participants