NationalSecurityAgency/ghidra · error · LSHException

Unknown tag: {el.getName()}

Error message

Unknown tag: {el.getName()}

What it means

Thrown by QueryNearestVector.restoreXml while deserializing a <querynearestvector> BSim request. After manage/simthresh/signifthresh, the only optional child element accepted is <vectormax>; any other start element raises LSHException. Like QueryNearest, this is strict schema enforcement during XML parsing.

Source

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

			fwrite.append("<vectormax>").append(SpecXmlUtils.encodeSignedInteger(vectormax)).append("</vectormax>\n");
		fwrite.append("</").append(name).append(">\n");
	}

	@Override
	public void restoreXml(XmlPullParser parser, LSHVectorFactory vectorFactory) throws LSHException {
		vectormax = 0;			// Default
		parser.start(name);
		manage.restoreXml(parser, vectorFactory);
		parser.start("simthresh");
		thresh = Double.parseDouble(parser.end().getText());
		parser.start("signifthresh");
		signifthresh = Double.parseDouble(parser.end().getText());
		while (parser.peek().isStart()) {
			XmlElement el = parser.start();
			if (el.getName().equals("vectormax"))
				vectormax = SpecXmlUtils.decodeInt(parser.end().getText());
			else
				throw new LSHException("Unknown tag: "+el.getName());

		}
		parser.end();
	}

}

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Use matching Ghidra/BSim versions on client and server.
  2. If you have a QueryNearest-style payload, send it as <querynearest>, not <querynearestvector>.
  3. Pre-validate that child elements of the body are only <vectormax> before calling restoreXml.
  4. Regenerate the XML from a QueryNearestVector object via saveXml rather than hand-authoring.

Example fix

// before
QueryNearestVector q = new QueryNearestVector();
q.restoreXml(parser, vectorFactory); // unknown tag

// after - regenerate from object instead of feeding alien XML
QueryNearestVector q = new QueryNearestVector();
q.thresh = 0.7;
q.signifthresh = 0.0;
q.vectormax = 50;
StringWriter sw = new StringWriter();
q.saveXml(sw);
// parse sw.toString() back - guaranteed schema-valid
Defensive patterns

Strategy: validation

Validate before calling

// QueryNearestVector accepts only <vectormax> after the fixed children
Set<String> allowed = Set.of("vectormax");
// pre-walk body starts and verify each name is in `allowed` before restoreXml

Type guard

static boolean isKnownQueryNearestVectorChild(String tag) {
    return "vectormax".equals(tag);
}

Try / catch

try {
    q.restoreXml(parser, vectorFactory);
} catch (LSHException e) {
    if (e.getMessage().startsWith("Unknown tag:")) {
        // likely a QueryNearest payload fed to a vector query parser
        throw new LSHException("Wrong query type or version: " + e.getMessage());
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling QueryNearestVector.restoreXml(parser, vectorFactory) where the XML body contains an element other than <vectormax>. Typically a version mismatch (a newer client serializes a tag like <categories> or <exefilter> that QueryNearestVector does not support) or corrupt/hand-edited XML.

Common situations: BSim client/server version skew. Confusing QueryNearest XML (which supports more tags) with QueryNearestVector XML. Manually authored request XML with extra elements.

Related errors


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