Budibase/budibase · error
REST query path must remain on the datasource origin
Error message
REST query path must remain on the datasource origin
What it means
assertSameOrigin enforces that the final request URL of a REST query stays on the origin of the datasource configuration. It compares the origin of the composed URL against the origins derived from this.config.url and any rawPath; if any differ, it throws 'REST query path must remain on the datasource origin'. This prevents queries from being redirected to arbitrary hosts - an SSRF/open-redirect protection for stored REST datasources.
Source
Thrown at packages/server/src/integrations/rest.ts:717
}
}
private assertSameOrigin(url: string, rawPath: string | undefined) {
const finalOrigin = this.getOrigin(url)
const expectedOriginUrls: string[] = []
if (this.config.url) {
expectedOriginUrls.push(this.getUrl())
}
if (rawPath !== undefined) {
expectedOriginUrls.push(this.getUrl(rawPath))
}
const isCrossOrigin = expectedOriginUrls.some(
expectedUrl => this.getOrigin(expectedUrl) !== finalOrigin
)
if (isCrossOrigin) {
throw new Error("REST query path must remain on the datasource origin")
}
}
private mergedQueryParams(fields: RestQuery, config: RestPreviewConfig) {
const queryParams = fields.queryString ? qs.decode(fields.queryString) : {}
return { ...(config.defaultQueryParameters || {}), ...queryParams }
}
private composeUrl(fields: RestQuery, config: RestPreviewConfig): string {
const { path = "", queryString = "", pagination, paginationValues } = fields
const defaultQueryParameters = config.defaultQueryParameters || {}
let mergedQueryString = queryString
if (Object.keys(defaultQueryParameters).length > 0) {
mergedQueryString = qs.encode(this.mergedQueryParams(fields, config))
}
return this.getUrl(
path,View on GitHub (pinned to a81a902e9a)
Solutions
- Make the query path relative and same-origin: use '/resource' instead of an absolute 'https://other-host/resource'
- If pagination returns absolute URLs on a different origin, use relative pagination parameters (offset/cursor fields) instead of following the next-URL directly
- Align scheme and host: set the datasource url to the actual API origin (https and correct host/port) used by the path
- If the API genuinely serves data across subdomains, create a separate REST datasource per origin
- Strip absolute next-links from pagination config so composed URLs derive only from the datasource base
Example fix
// before
{ path: "https://cdn.example.com/v2/users" } // config url: https://api.example.com
// after
{ path: "/v2/users" } Defensive patterns
Strategy: validation
Validate before calling
function isSameOrigin(base, target) {
const b = new URL(base), t = new URL(target, base)
return b.origin === t.origin
}
if (!isSameOrigin(datasourceUrl, pathOrNextUrl)) {
throw new Error("path must stay on the datasource origin")
} Type guard
function isRelativePath(p) {
return typeof p === "string" && !/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(p)
} Try / catch
try {
const result = await restQuery.execute()
} catch (e) {
if (e.message === "REST query path must remain on the datasource origin") {
// rewrite path to relative, or configure a separate datasource for that origin
} else { throw e }
} Prevention
- Always use relative paths in REST query paths; never absolute URLs to other hosts
- Prefer relative/cursor pagination parameters over following absolute next-URLs returned by APIs
- Match scheme, host and port between the datasource url and every path used
- Create one datasource per origin instead of cross-origin paths
When it happens
Trigger: Calling buildRequest where the fields.path (or pagination next-URL) resolves to a different scheme/host/port than the datasource's configured url - e.g. path is an absolute URL to another host, or a pagination 'next' link returned by the API points to a different origin than the datasource base URL.
Common situations: API's pagination response includes absolute 'next' URLs on a CDN or different subdomain than the configured datasource base URL; query path built with an absolute URL (https://other-api.com/...) instead of a relative path; http vs https mismatch between config url and path; port mismatch (localhost:3000 vs localhost:4001) in local dev.
Related errors
- Only HTTP(S) URLs are allowed.
- URL must not include credentials.
- Plugin URL must use HTTPS.
- Only HTTP(S) URLs are allowed for query import
- IMAP host is blocked or could not be resolved safely
AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29).
Data as JSON: /api/errors/54e93888f3de8ea4.
Report an issue: GitHub.