NationalSecurityAgency/ghidra · error · LSHException

Unknown tag: {el.getName()}

Error message

Unknown tag: {el.getName()}

What it means

Thrown by QueryNearest.restoreXml while deserializing a <querynearest> BSim request. After parsing manage, simthresh, signifthresh and max, the parser loops over remaining start elements and only accepts <vectormax>, <categories>, and <exefilter>; any other tag name raises LSHException. This is strict schema validation so that malformed or version-mismatched XML fails fast instead of being silently dropped.

Source

Thrown at Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/query/protocol/QueryNearest.java:140

		signifthresh = Double.parseDouble(parser.end().getText());
		parser.start("max");
		max = SpecXmlUtils.decodeInt(parser.end().getText());
		while (parser.peek().isStart()) {
			XmlElement el = parser.peek();
			if (el.getName().equals("vectormax")) {
				parser.start();
				vectormax = SpecXmlUtils.decodeInt(parser.end().getText());
			}
			else if (el.getName().equals("categories")) {
				parser.start();
				fillinCategories = SpecXmlUtils.decodeBoolean(parser.end().getText());
			}
			else if (el.getName().equals("exefilter")) {
				bsimFilter = new BSimFilter();
				bsimFilter.restoreXml(parser);
			}
			else
				throw new LSHException("Unknown tag: "+el.getName());
				
		}
		parser.end();
	}

}

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Ensure the client and server run the same Ghidra/BSim version so the serialized XML schema matches the parser.
  2. Validate the XML against the expected tag set (vectormax, categories, exefilter) before calling restoreXml.
  3. Inspect the offending tag name in the exception message to identify which extra field was serialized and remove or downgrade it.
  4. If intercepting traffic, regenerate the request with a QueryNearest object via saveXml instead of hand-authoring XML.

Example fix

// before
QueryNearest q = new QueryNearest();
q.restoreXml(parser, vectorFactory); // throws on unknown tag

// after
Set<String> allowed = Set.of("vectormax", "categories", "exefilter", "simthresh", "signifthresh", "max");
// pre-scan: ensure remaining child tags are within the allowed set
QueryNearest q = new QueryNearest();
try {
    q.restoreXml(parser, vectorFactory);
} catch (LSHException e) {
    throw new LSHException("Schema mismatch - check BSim client/server version: " + e.getMessage());
}
Defensive patterns

Strategy: validation

Validate before calling

Set<String> allowed = Set.of("vectormax", "categories", "exefilter");
// pre-walk child starts of the querynearest element and assert names are in `allowed`
// before calling restoreXml

Type guard

static boolean isKnownQueryNearestChild(String tag) {
    return Set.of("vectormax", "categories", "exefilter").contains(tag);
}

Try / catch

try {
    q.restoreXml(parser, vectorFactory);
} catch (LSHException e) {
    if (e.getMessage().startsWith("Unknown tag:")) {
        throw new LSHException(
            "BSim schema mismatch (client/server version?): " + e.getMessage());
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling QueryNearest.restoreXml(parser, vectorFactory) on XML that contains an element other than vectormax/categories/exefilter after <max>. Happens when the client and server disagree on the request schema (e.g. newer client serializes a tag the older parser doesn't know), or when hand-edited/corrupt XML is fed in.

Common situations: Version skew between a BSim client and server (a field added in a newer Ghidra release). Feeding a query XML document produced by a different BSim dialect. Manually constructing XML and misspelling a tag.

Related errors


AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14). Data as JSON: /api/errors/624b4eb9cb088111. Report an issue: GitHub.