languagetool-org/languagetool · error · BadRequestException
'callback' value must match [a-zA-Z]+: '{callback}'
Error message
'callback' value must match [a-zA-Z]+: '{callback}' What it means
The JSONP 'callback' parameter must consist only of ASCII letters ([a-zA-Z]+); anything else (digits, underscores, dots, brackets) is rejected to prevent injection into the JSONP response body. The constructor of the request-validation class enforces this regex whenever callback is non-null.
Source
Thrown at languagetool-server/src/main/java/org/languagetool/server/TextChecker.java:1090
QueryParams(List<Language> altLanguages, List<String> enabledRules, List<String> disabledRules, List<CategoryId> enabledCategories, List<CategoryId> disabledCategories,
boolean useEnabledOnly, boolean useQuerySettings, boolean allowIncompleteResults, boolean enableHiddenRules, boolean premium, boolean enableTempOffRules, JLanguageTool.Mode mode, JLanguageTool.Level level, Set<ToneTag> toneTags, @Nullable String callback, boolean inputLogging) {
this.altLanguages = Objects.requireNonNull(altLanguages);
this.enabledRules = enabledRules;
this.disabledRules = disabledRules;
this.enabledCategories = enabledCategories;
this.disabledCategories = disabledCategories;
this.useEnabledOnly = useEnabledOnly;
this.useQuerySettings = useQuerySettings;
this.allowIncompleteResults = allowIncompleteResults;
this.enableHiddenRules = enableHiddenRules;
this.premium = premium;
this.enableTempOffRules = enableTempOffRules;
this.regressionTestMode = enableTempOffRules;
this.mode = Objects.requireNonNull(mode);
this.level = Objects.requireNonNull(level);
this.toneTags = toneTags;
if (callback != null && !callback.matches("[a-zA-Z]+")) {
throw new BadRequestException("'callback' value must match [a-zA-Z]+: '" + callback + "'");
}
this.callback = callback;
this.inputLogging = inputLogging;
}
@Override
public int hashCode() {
return new HashCodeBuilder()
.append(altLanguages)
.append(enabledRules)
.append(disabledRules)
.append(enabledCategories)
.append(disabledCategories)
.append(useEnabledOnly)
.append(useQuerySettings)
.append(allowIncompleteResults)
.append(enableHiddenRules)
.append(premium)View on GitHub (pinned to 2e990059ce)
Solutions
- Use a callback of letters only, e.g. 'myCallback' or 'jsonpCallback'
- Sanitize/strip non-letter characters from the callback before sending
- Generate a letters-only random suffix if uniqueness is needed (e.g. 'callbackXyzAbc')
- Drop the callback parameter entirely and consume plain JSON with fetch/axios
Example fix
// before
params.put("callback", "jQuery123_456");
// after
params.put("callback", "jQueryCallback"); Defensive patterns
Strategy: validation
Validate before calling
if (!/^[a-zA-Z]+$/.test(callback)) throw new Error('callback must be letters only'); Type guard
const isValidCallback = (cb) => typeof cb === 'string' && /^[a-zA-Z]+$/.test(cb);
Prevention
- Strip non-letters from generated callback names
- Prefer plain JSON over JSONP in modern clients
- Add a unit test asserting callback format before requests
When it happens
Trigger: Calling /v2/check with callback=my_func, callback=cb1, callback=jQuery123... — any callback containing non-letter characters.
Common situations: Frameworks auto-generating callbacks like jQuery12345_ or __jsonp_cb_0; developers adding underscores for readability; client-side JSONP helpers that append counters.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- 'language' parameter missing
- Set only 'text' or 'data' parameter, not both
- 'data' key in JSON requires either 'text' or 'annotation' ke
- 'data' key in JSON requires 'text' or 'annotation' key
- Only either 'text' or 'markup' are supported in an object in
AI-assisted analysis of languagetool-org/languagetool@2e990059ce (2026-09-06).
Data as JSON: /api/errors/71cba4df5e273e93.
Report an issue: GitHub.