evanw/esbuild · error
could not decode percent-escaped data
Error message
could not decode percent-escaped data: %s
What it means
When esbuild resolves a data: URL without the ;base64 flag, it calls url.PathUnescape on the payload to decode percent-encoded characters. This error fires when the data contains malformed percent-escape sequences such as a lone '%' or '%ZZ' (non-hex digits after the percent sign).
Solutions
- Ensure every '%' in the data URL is followed by exactly two hex digits (e.g. '%25' for a literal percent sign)
- Generate data URLs using encodeURIComponent or encodeURI to produce valid percent escapes
- Use base64 encoding instead of percent-encoding if the data contains many special characters
Example fix
// before import x from 'data:text/javascript,console.log(50%)' // after import x from 'data:text/javascript,console.log(50%25)'
Defensive patterns
Strategy: validation
Validate before calling
function makeDataUrl(mimeType, content) {
// encodeURIComponent produces valid percent-escapes
return `data:${mimeType},${encodeURIComponent(content)}`
}
function isValidPercentEncoding(str) {
return !/%[^0-9a-fA-F]|%[0-9a-fA-F][^0-9a-fA-F]/.test(str)
}
const url = makeDataUrl('text/javascript', 'export default 1')
// safe to import Prevention
- Use encodeURIComponent or encodeURI to produce data URL payloads
- Manually check for stray '%' not followed by two hex digits in data URLs
- Use base64 encoding if the data contains many percent signs
When it happens
Trigger: Importing a data: URL (without ;base64) containing a percent sign not followed by two hex digits, e.g. 'data:text/javascript,console.log(50%)'.
Common situations: Data URLs with literal percent signs (like in math expressions or formatting), truncated percent escapes, or data that was not properly URL-encoded.
Related errors
- could not decode base64 data
- Cannot compute relative path from
- Cannot serve a disposed context
- Cannot serve without an output path
- Cannot watch a disposed context
AI-assisted analysis of evanw/esbuild@f6058f8364 (2026-08-09).
Data as JSON: /api/errors/0c8ef6dcd3a50ffa.
Report an issue: GitHub.
Appendix: source
Thrown at internal/resolver/dataurl.go:73
default:
return MIMETypeUnsupported
}
}
func (parsed DataURL) DecodeData() (string, error) {
// Try to read base64 data
if parsed.isBase64 {
bytes, err := base64.StdEncoding.DecodeString(parsed.data)
if err != nil {
return "", fmt.Errorf("could not decode base64 data: %s", err.Error())
}
return string(bytes), nil
}
// Try to read percent-escaped data
content, err := url.PathUnescape(parsed.data)
if err != nil {
return "", fmt.Errorf("could not decode percent-escaped data: %s", err.Error())
}
return content, nil
}
View on GitHub (pinned to f6058f8364)