This frustratingly vague error is Safari’s telling you that a string argument to a DOM API didn’t match the expected format. Unlike Chrome, which provides specific messages like “unexpected token >”, Safari uses this single generic message for multiple problems.
The error is WebKit’s standard DOM Exception 12 (SYNTAX_ERR), and it affects all WebKit-based browsers including Safari on macOS and iOS, plus Chrome on iOS (which uses WebKit due to Apple’s App Store requirements).
The Problem
“The string did not match the expected pattern” is a SyntaxError that Safari throws when string validation fails across multiple unrelated APIs. The same error message appears whether you’re passing a malformed CSS selector to querySelector(), trying to parse non-JSON data, or setting an invalid value on a DOM property.
// Invalid CSS selector
document.querySelector('[role="spinbutton');
// JSON parsing of non-JSON response
fetch('/api/text-endpoint').then(res => res.json());
// Invalid contentEditable value
element.contentEditable = undefined;
Key point: This error masks completely different root causes. When you see it in your error monitoring, you’ll need to examine the stack trace to identify which API triggered it.
Understanding the Root Cause
“The string did not match the expected pattern” stems from WebKit’s strict validation of string arguments across several APIs:
1. Invalid CSS Selectors in querySelector
Most common cause: Safari enforces CSS selector syntax more strictly than Chrome. Missing brackets, unquoted attribute values, or malformed selectors trigger this error where Chrome might silently handle them.
How to identify: Stack trace points to querySelector or querySelectorAll calls.
2. JSON Parsing Failures with fetch
Calling response.json() on a response containing non-JSON data (like HTML error pages or plain text) triggers this error. Chrome provides the more helpful “unexpected token X in JSON at position 0.”
How to identify: Stack trace shows .json() method calls, often in fetch promise chains.
3. DOM API with Invalid Values
Setting a DOM properties with undefined or other invalid values throws this error in Safari. The HTML specification often has requirements for what valid valies can be, and Safari strictly enforces this.
How to identify: Stack trace points to code assigning values HTML elements or nodes.
4. Performance.measure() with Null Arguments
Safari 12.x and earlier reject null as arguments to performance.measure(). This notably affected Next.js applications before version 9.0.4.
How to identify: Stack trace shows performance.measure() calls, often in framework code or performance monitoring libraries.
5. Web Audio Sample Rate Restrictions
Safari’s Web Audio API is stricter about sample rates. Creating an OfflineAudioContext with non-standard sample rates like 22050 Hz can trigger this error.
How to identify: Stack trace points to OfflineAudioContext or webkitOfflineAudioContext creation.
How to Fix “The string did not match the expected pattern”
Quick Troubleshooting Checklist
- Check the stack trace to identify which API triggered the error
- Validate CSS selectors have proper bracket closure and quoted attributes
- Verify API responses are actually JSON before calling
.json() - Use explicit string values for contentEditable (
"true","false","inherit") - Test with Safari’s Web Inspector to reproduce the issue
- Check for Safari-specific API restrictions in your code
Follow these steps based on which API is causing the error:
Step 1: Fix Invalid CSS Selectors
Ensure all CSS selectors have proper syntax with closed brackets and quoted attribute values:
// FAILS in Safari - missing closing bracket
document.querySelector('[role="spinbutton');
// FAILS in Safari - unquoted attribute value
document.querySelector('script[type=text/javascript]');
// WORKS in all browsers
document.querySelector('[role="spinbutton"]');
document.querySelector('script[type="text/javascript"]');
For dynamically generated selectors, validate them before use:
function safeQuerySelector(selector) {
try {
return document.querySelector(selector);
} catch (error) {
console.error('Invalid selector:', selector, error);
return null;
}
}
Step 2: Handle JSON Parsing Defensively
Check the response content before parsing, or use defensive JSON parsing:
async function safeFetch(url) {
const response = await fetch(url);
// Check content-type header first
const contentType = response.headers.get('content-type');
if (!contentType || !contentType.includes('application/json')) {
throw new Error('Response is not JSON');
}
// Parse with error handling
const text = await response.text();
try {
return JSON.parse(text);
} catch (error) {
console.error('Invalid JSON:', text.substring(0, 100));
throw new Error('Response was not valid JSON');
}
}
Step 3: Use Valid DOM Values
Always use explicit string values for the contentEditable property:
// FAILS in Safari - undefined gets coerced to "undefined" string
element.contentEditable = undefined;
element.contentEditable = someVariable; // Dangerous if variable is undefined
// WORKS in all browsers - use explicit strings
element.contentEditable = "true";
element.contentEditable = "false";
element.contentEditable = "inherit";
// Safe pattern when working with variables
function setEditable(element, isEditable) {
element.contentEditable = isEditable ? "true" : "false";
}
Step 4: Fix Performance.measure() Calls
Use valid performance mark names instead of null:
// FAILS in Safari 12.x and earlier
performance.measure('my-measure', null, 'endMark');
// WORKS in all browsers - use navigationStart instead of null
performance.measure('my-measure', 'navigationStart', 'endMark');
Step 5: Use Standard Audio Sample Rates
When working with the Web Audio API, stick to standard sample rates:
// FAILS in Safari - non-standard sample rate
new webkitOfflineAudioContext(1, 100, 22050);
// WORKS in all browsers - standard sample rates
new webkitOfflineAudioContext(1, 100, 44100); // CD quality
new webkitOfflineAudioContext(1, 100, 48000); // DVD quality
Step 6: Monitor Production Errors
Since this error can have multiple causes, production monitoring helps you identify which specific scenario is affecting your users. Error monitoring services like TrackJS capture the full stack trace and browser context, letting you pinpoint whether users are hitting selector issues, JSON parsing failures, or something else entirely.
Safari’s DevTools don’t allow copying stack traces as text, making remote error monitoring particularly valuable for diagnosing these issues in production.
When to Ignore This Error
This error usually indicates a real problem that should be fixed, but consider the context:
- Third-party scripts: If the error originates from analytics or widget code you don’t control
- Framework internals: Some older framework versions trigger this in Safari (check for updates)
- Edge cases: Rare user interactions that don’t affect core functionality
However, investigate when you see:
- High frequency: Many users hitting the same error
- Core functionality affected: Errors blocking essential user workflows
- Consistent patterns: Errors from specific pages or features you maintain
Summary
Safari’s “The string did not match the expected pattern” error is WebKit’s generic DOM Exception 12 message, thrown when string validation fails across multiple APIs. The most common triggers are invalid CSS selectors, JSON parsing of non-JSON responses, contentEditable with invalid values, and Performance.measure() with null arguments.
The key to fixing this error is examining the stack trace to identify which API triggered it. Safari enforces stricter validation than Chrome, so code that works elsewhere may fail in Safari. Always validate inputs to DOM APIs and test in Safari before deploying to production.
Catch Safari-specific errors before your users do with TrackJS Error Monitoring. Get detailed stack traces and browser context to quickly identify and fix cross-browser compatibility issues.