Area: Ingestion Issues
Sub-Area: Looker Connector — Embed URL Validation
Issue
When ingesting Looker assets, DataHub may fail to ingest dashboards whose IDs contain spaces (for example,
LookML dashboards named in the pattern model::Dashboard Name With Spaces). The Looker connector
constructs embed preview URLs by interpolating the raw dashboard ID directly into a URL string without
percent-encoding it. Starting with DataHub v2.2.0, a server-side URL validator was introduced to block
dangerous embed URL schemes. That validator calls Java's java.net.URI parser before inspecting
the scheme, and java.net.URI throws a URISyntaxException on any unencoded space in
the path, causing the entire metadata record — and, because records are batched, up to 100 unrelated records
in the same batch — to be rejected. Dashboards that ingested without issue on earlier versions will begin
failing after an upgrade to v2.2.0 or later.
Error Messages
Invalid URL syntax for 'renderUrl': https://<your-looker-host>/embed/dashboards/<model>::<Dashboard Name With Spaces>
You Might Be Asking
- Why did Looker ingestion suddenly start failing after a DataHub upgrade even though nothing changed in my Looker environment?
- Is the
::separator in LookML dashboard IDs causing the failure, or is it something else? - Why are dashboards that have no spaces in their names also failing or disappearing from the catalog?
- Can I ingest all LookML dashboards, including those with spaces in their IDs, without using a deny pattern?
Solution
The root cause is an unencoded space character in the embed URL — not the ::
separator, which is valid in a URL path and parses fine. Because :: is the standard separator
in every LookML dashboard ID, a deny pattern written as .*::.* (the most intuitive response to
the error) will exclude all LookML dashboards, not just the ones with spaces. Choose one of the two
config-only remedies below.
Option 1 — Disable embed URL extraction (recommended if you need all dashboards to ingest)
Setting extract_embed_urls: false prevents the connector from constructing the embed preview URL
entirely. No URL is generated, so none can be rejected by the validator. All dashboards — including those
with spaces in their IDs — will ingest successfully. The trade-off is that the embed preview tab will not be
populated for newly ingested Looker assets; previously stored previews are unaffected.
Add the following to your Looker source configuration and remove any existing dashboard_pattern deny block that was added as a workaround:
source:
type: looker
config:
base_url: "https://<your-looker-host>"
# ... other config ...
extract_embed_urls: false
Option 2 — Narrow the deny pattern to only the affected dashboards
If embed previews are important to you, you can narrow the deny pattern to target only the specific dashboard
IDs that contain spaces, leaving all other LookML dashboards unaffected. Replace the broad
.*::.* pattern with exact matches for the problem dashboards:
source:
type: looker
config:
base_url: "https://<your-looker-host>"
# ... other config ...
dashboard_pattern:
deny:
- "^model_name::Dashboard Name With Spaces$"
- "^other_model::Another Broken Dashboard$"
Substitute the actual dashboard IDs that contain spaces. All other dashboards, including those whose IDs
contain :: but no spaces, will ingest normally.
Important: stateful ingestion warning
If stateful_ingestion.enabled is true in your recipe, do not
expand the allow-set (by removing or narrowing a deny pattern) while stateful ingestion is turned on and a
broad deny pattern is still active. Assets that were excluded by the deny pattern will be marked as deleted
on the next run and may be permanently removed by the garbage collector after 30 days. Narrow or remove the
deny pattern before re-enabling stateful ingestion.
Permanent fix
A connector-level fix is tracked in the DataHub OSS repository. The fix percent-encodes the dashboard ID
when constructing the embed URL using urllib.parse.quote(dashboard_id, safe=':'). The
safe=':' argument is required; using safe='' would encode the colons to
%3A, which causes the resulting URL to fail to resolve in Looker even though it passes the Java
URI parser. Once this fix is released, neither workaround above will be necessary, and
extract_embed_urls can be re-enabled if it was disabled.
Additional Notes
- This regression was introduced in DataHub v2.2.0 when server-side embed URL validation was added (OSS PR #19299, "fix(embed): reject dangerous renderUrl schemes to prevent stored XSS"). Deployments on v2.1.x and earlier are not affected.
-
The failing character is the space, not
::. URLs of the form/embed/dashboards/model::nameparse without error; only a space in the path triggers the exception. -
Because the Looker connector sends metadata in batches (default
max_per_batch: 100), a single rejected dashboard URL can cause up to 100 unrelated metadata records in the same batch to be silently dropped. Check your ingestion run reports for unexpected gaps in charts or datasets even when only a few dashboards are affected. -
With
stateful_ingestion.enabled: false(the default for many recipes), assets excluded by a deny pattern are not deleted from the catalog — they simply stop updating. This means the problem may not be visible in the UI even when a large number of dashboards are being skipped. -
The same
java.net.URIrejection can affect any connector that emits anEmbedClassaspect with a URL containing characters that are illegal in a URI path, not just Looker. The Mode connector is another known emitter of embed aspects.
Related Documentation
- Looker Ingestion Source — Config Details
- Looker Ingestion Source Overview
- Stateful Ingestion Guide
- GitHub Issue: Looker connector embed URL encoding
Tags: looker, ingestion, embed-url, url-validation, lookml-dashboards, renderUrl, extract-embed-urls, dashboard-pattern, v2.2.0, regression