languagetool-org/languagetool · error · BadRequestException
'text' cannot be used with 'interpretAs' (only 'markup' can)
Error message
'text' cannot be used with 'interpretAs' (only 'markup' can):
What it means
In the 'annotation' list of the /v2/check data parameter, 'interpretAs' is only allowed together with 'markup'. If an object has both 'text' and 'interpretAs', LanguageTool throws BadRequestException because there is no meaningful way to reinterpret explicit text.
Source
Thrown at languagetool-server/src/main/java/org/languagetool/server/ApiV2.java:486
}
return textBuilder.build();
}
private AnnotatedText getAnnotatedTextFromJson(JsonNode data) {
AnnotatedTextBuilder atb = new AnnotatedTextBuilder();
// Expected format:
// annotation: [
// {text: 'text'},
// {markup: '<b>'}
// {text: 'more text'},
// {markup: '</b>'}
// ]
//
for (JsonNode node : data.get("annotation")) {
if (node.get("text") != null && node.get("markup") != null) {
throw new BadRequestException("Only either 'text' or 'markup' are supported in an object in 'annotation' list, not both: " + node);
} else if (node.get("text") != null && node.get("interpretAs") != null) {
throw new BadRequestException("'text' cannot be used with 'interpretAs' (only 'markup' can): " + node);
} else if (node.get("text") != null) {
atb.addText(node.get("text").asText());
} else if (node.get("markup") != null) {
if (node.get("interpretAs") != null) {
atb.addMarkup(node.get("markup").asText(), node.get("interpretAs").asText());
} else {
atb.addMarkup(node.get("markup").asText());
}
} else {
throw new BadRequestException("Only 'text' and 'markup' are supported in 'annotation' list: " + node);
}
}
return atb.build();
}
String getLanguages() throws IOException {
StringWriter sw = new StringWriter();
try (JsonGenerator g = factory.createGenerator(sw)) {View on GitHub (pinned to 2e990059ce)
Solutions
- Remove 'interpretAs' from text objects.
- If reinterpretation is needed, convert the entry to {"markup":"...","interpretAs":"..."}.
- Validate the annotation JSON client-side before sending.
Example fix
// before
{"annotation":[{"text":"gr8","interpretAs":"great"}]}
// after
{"annotation":[{"markup":"gr8","interpretAs":"great"}]} Defensive patterns
Strategy: validation
Validate before calling
for (const n of annotation) {
if (n.text != null && n.interpretAs != null) throw new Error('interpretAs is only valid with markup: ' + JSON.stringify(n));
} Type guard
function canUseInterpretAs(n) { return n.markup != null || n.interpretAs == null; } Try / catch
try {
const res = await fetch('/v2/check', { method: 'POST', body: form });
if (res.status === 400) throw new Error(await res.text());
} catch (e) {
console.error('annotation payload invalid:', e.message);
} Prevention
- Only emit interpretAs next to markup.
- Strip interpretAs from text nodes in your payload builder.
- Add a unit test for annotation payload generation.
When it happens
Trigger: POSTing data like {"annotation":[{"text":"Hello","interpretAs":"Hi"}]} — a node with both non-null 'text' and 'interpretAs' keys (and no 'markup').
Common situations: Copying the markup+interpretAs pattern onto text objects; template-based payload builders that always emit interpretAs.
Related errors
- Only either 'text' or 'markup' are supported in an object in
- Only 'text' and 'markup' are supported in 'annotation' list:
- 'data' key in JSON requires either 'text' or 'annotation' ke
- 'data' key in JSON requires 'text' or 'annotation' key
- Invalid format for 'preferredVariants', expected a dash as i
AI-assisted analysis of languagetool-org/languagetool@2e990059ce (2026-09-06).
Data as JSON: /api/errors/a66fe2dc67ead6c5.
Report an issue: GitHub.