GoogleChrome/lighthouse · warning · Error

"$" should only be used at the end of the pattern

Error message

"$" should only be used at the end of the pattern

What it means

Thrown by verifyDirective() when a '$' end-of-pattern anchor character appears anywhere except the last position of an Allow or Disallow value. In robots.txt, '$' is a supported extension meaning 'end of URL path' — it is only meaningful and valid at the end. A '$' in the middle is a syntax error that crawlers would misinterpret.

Source

Thrown at core/audits/seo/robots-txt.js:100

    if (!SITEMAP_VALID_PROTOCOLS.has(sitemapUrl.protocol)) {
      throw new Error('Invalid sitemap URL protocol');
    }
  }

  if (directiveName === DIRECTIVE_USER_AGENT && !directiveValue) {
    throw new Error('No user-agent specified');
  }

  if (directiveName === DIRECTIVE_ALLOW || directiveName === DIRECTIVE_DISALLOW) {
    if (directiveValue !== '' && directiveValue[0] !== '/' && directiveValue[0] !== '*') {
      throw new Error('Pattern should either be empty, start with "/" or "*"');
    }

    const dollarIndex = directiveValue.indexOf('$');

    if (dollarIndex !== -1 && dollarIndex !== directiveValue.length - 1) {
      throw new Error('"$" should only be used at the end of the pattern');
    }
  }
}

/**
 * @param {string} line single line from a robots.txt file
 * @throws will throw an exception if given line has errors
 * @return {{directive: string, value: string}|null}
 */
function parseLine(line) {
  const hashIndex = line.indexOf('#');

  if (hashIndex !== -1) {
    line = line.substr(0, hashIndex);
  }

  line = line.trim();

View on GitHub (pinned to 9515cd4e58)

Solutions

  1. Move '$' to the end of the pattern, e.g. 'Disallow: /foo$' to match paths ending in /foo
  2. If the literal '$' is needed in a path, use '*' wildcard matching instead since '$' cannot appear mid-pattern
  3. Remove the '$' entirely if no end-anchoring is needed

Example fix

// before
Disallow: /download$file

// after
Disallow: /download*
Defensive patterns

Strategy: validation

Validate before calling

// Validate that '$' only appears at the end of patterns
function validateDollarAnchor(content) {
  const lines = content.split(/\r\n|\r|\n/);
  const errors = [];
  lines.forEach((line, idx) => {
    const trimmed = line.split('#')[0].trim();
    const match = /^(allow|disallow)\s*:\s*(.*)$/i.exec(trimmed);
    if (match) {
      const value = match[2];
      const dollarIdx = value.indexOf('$');
      if (dollarIdx !== -1 && dollarIdx !== value.length - 1) {
        errors.push(`Line ${idx + 1}: '$' must be at the end of the pattern`);
      }
    }
  });
  return errors;
}

Try / catch

try {
  parseLine(line);
} catch (e) {
  // e.message === '"$" should only be used at the end of the pattern'
  robotsErrors.push({ line, message: e.message });
}

Prevention

When it happens

Trigger: A robots.txt line like 'Disallow: /foo$bar' where '$' appears mid-pattern. The check verifies `dollarIndex !== -1 && dollarIndex !== directiveValue.length - 1`, so any '$' that is not the final character triggers the throw.

Common situations: Developer treats '$' as a regex variable or literal character rather than a robots.txt end-anchor. Copying regex patterns verbatim into robots.txt. A URL containing literal '$' characters that the developer tried to match without escaping.

Related errors


AI-assisted analysis of GoogleChrome/lighthouse@9515cd4e58 (2026-08-13). Data as JSON: /api/errors/4b60fd4278b098df. Report an issue: GitHub.