Docly Developers
Knowledge base Bug Resolved

request.completeUrl contains unencoded spaces

In shortFixed in production on 22 August 2026: request.completeUrl is now slugified like encodedUrl, so it no longer contains spaces. The request object carries eight URL members - raw or slugified, relative or absolute - and the table below shows which one to use where. Pages built before the fix may still avoid completeUrl; that is no longer necessary.
Applies to Hash templatesJavaScriptAPI
  1. What you'll see

    A canonical tag, an og:url, a sitemap entry or a Location header comes out containing literal spaces. Browsers often paper over it, so it survives a manual click-through and fails where nothing is watching: crawlers, link checkers, social preview fetchers and anything that compares the canonical against the requested URL.

    Measured before the fix, on a page stored at /Test files/zz-inventory.hash:

    request.completeUrl     // https://example.net/Test files/zz-inventory     <- spaces
    request.encodedUrl      // https://example.net/Test-files/zz-inventory     <- slugified

    The name reads like the most complete and therefore the most correct option. It is the most complete and the least suitable for output.

  2. What's actually happening

    There are eight URL members on request, and they are not eight variations on a theme. They are two axes crossed: raw or slugified, and relative or absolute.

    MemberValue for /Test files/zz-inventory.hash
    url, Url/Test-files/zz-inventory
    urlpath/Test-files/zz-inventory
    rawurl, rawUrl/Test files/zz-inventory
    completeUrlhttps://example.net/Test-files/zz-inventory
    encodedUrl, encodedFileUrlhttps://example.net/Test-files/zz-inventory
    siteUrlhttps://example.net/

    The capitalised pairs are aliases, not variants: url and Url carry the same value, as do rawurl and rawUrl. Either spelling works.

    The slugified forms are what the site actually serves — a folder named Test files is reachable at /Test-files/. The raw forms mirror the names on the drive, and are legitimate for matching against a drive path.

    completeUrl used to be the exception: until 22 August 2026 it did not slugify folder and file names, and returned https://example.net/Test files/zz-inventory. It is now slugified the same way as encodedUrl.

  3. What to do

    1. Choose by destination, not by name.

    You wantUse
    A link, canonical, og:url, sitemap entry or Location headerrequest.encodedUrl
    A site-relative link in markuprequest.url
    The site rootrequest.siteUrl (request.sitename is the name of the published folder, not the host)
    To read or write the file behind this requestrequest.filepath, request.folderpath
    To compare against a stored pathPick one family and stay in it — raw or slugified, never a mix

    2. completeUrl and encodedUrl are now encoded the same way, but they are not the same value: completeUrl is the actual request path (plus the query string in API calls), while encodedUrl is the page's address without a trailing /index or slash — they differ for the site root, folders and index pages. Older pages that avoid completeUrl do not need to change.

    3. Do not encode it yourself afterwards. Running completeUrl through an encoder produces %20 where the site serves a hyphen, so the result is a valid URL that resolves to nothing. The slug is a rename, not an escape. See Do not build file and image URLs by hand.

    4. Do not reach for host or domain. They are null, and because an unresolved or null name renders as an empty string rather than raising, a template that uses one produces a URL missing its host with no error anywhere. See Unresolved names in hash expressions render empty.

    5. Print the members rather than guessing between them. Which one you have is a one-request question — see Use a scratch hash file to test Docly functions.

Last reviewed 21 Aug 2026