different-ai/openwork · warning · PluginArchRouteFailure
invalid_return_path
invalid_return_path
Error message
GitHub install return path must be a safe relative path.
What it means
Thrown (400) by startGithubConnectorInstall when `returnPath` does not start with `/` or starts with `//`. The return path is used to redirect the user back after the GitHub OAuth/app-install round trip, so it must be a safe relative in-app path — absolute URLs or protocol-relative paths would enable open-redirect.
Source
Thrown at ee/apps/den-api/src/routes/org/plugin-system/store.ts:6871
await db.update(ConnectorAccountTable).set({
displayName: installation.displayName,
externalAccountRef: installation.accountLogin,
metadataJson: {
...(existingRows[0].metadataJson ?? {}),
...metadata,
},
status: "active",
updatedAt: new Date(),
}).where(eq(ConnectorAccountTable.id, existingRows[0].id))
return getConnectorAccountDetail(input.context, existingRows[0].id)
}
export async function startGithubConnectorInstall(input: { context: PluginArchActorContext; returnPath: string }) {
const returnPath = input.returnPath.trim()
if (!returnPath.startsWith("/") || returnPath.startsWith("//")) {
throw new PluginArchRouteFailure(400, "invalid_return_path", "GitHub install return path must be a safe relative path.")
}
let app: Awaited<ReturnType<typeof getGithubAppSummary>>
try {
app = await getGithubAppSummary({ config: githubConnectorAppConfig() })
} catch (error) {
wrapGithubConnectorError(error)
}
const state = createGithubInstallStateToken({
orgId: input.context.organizationContext.organization.id,
returnPath,
secret: env.betterAuthSecret,
userId: input.context.organizationContext.currentMember.userId,
})
return {
redirectUrl: buildGithubAppInstallUrl({ app, state }),
state,View on GitHub (pinned to 2b7df46e8a)
Solutions
- Pass a root-relative path that begins with a single `/`, e.g. `/org/settings/connectors`.
- On the client, derive the value from `new URL(window.location.href).pathname + search` rather than the full href.
- Sanitize any stored/deep-link return path before starting the install (strip scheme/host, ensure leading single slash).
Example fix
// before
await startGithubConnectorInstall({ returnPath: window.location.href }) // 'https://host/org/...' -> invalid_return_path
// after
const u = new URL(window.location.href)
await startGithubConnectorInstall({ returnPath: u.pathname + u.search }) // '/org/settings/connectors?x=1' Defensive patterns
Strategy: validation
Validate before calling
function safeReturnPath(p: string): string {
const t = p.trim()
if (!t.startsWith('/') || t.startsWith('//')) throw new Error(`returnPath must be a relative path starting with a single '/', got: ${p}`)
return t
} Type guard
function isSafeRelativePath(p: string): boolean { return p.startsWith('/') && !p.startsWith('//') } Try / catch
try {
await startGithubConnectorInstall({ returnPath })
} catch (e) {
if (e instanceof PluginArchRouteFailure && e.code === 'invalid_return_path') {
await startGithubConnectorInstall({ returnPath: '/org/settings/connectors' })
} else throw e
} Prevention
- Derive return paths from location.pathname, never location.href
- Centralize return-path construction in one sanitized helper
- Add a unit test asserting no scheme or protocol-relative forms reach the API
When it happens
Trigger: Calling startGithubConnectorInstall with returnPath like "https://evil.com", "//evil.com", "" (empty after trim), or a path missing the leading slash ("dashboard/connectors").
Common situations: Frontend builds the return path by string concatenation and drops the leading slash; passing a full URL from window.location instead of pathname; SSRF/open-redirect guards in other tools sending absolute URLs.
Related errors
- An enterprise MCP OAuth redirect URI cannot contain credenti
- Agent context diagnostics timeout must be between 1 ms and 3
- External URL protocol "${parsed.protocol}" is not allowed.
- Invalid cloud provider sync response.
- Invalid cloud provider sync status.
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/c8fecbdd928e11eb.
Report an issue: GitHub.