lxml does not currently set ctxt->error, because all errors are collected globally. The check above prevents libxml2 from reporting the error at all in that case, although it would work if the check wasn't there. Meaning, it's really just exactly this error message that does not go through. Thanks for stumbling over it. :)
Looks like a bug in libxml2 to me. It has this code in valid.c:
2636 if ((ctxt != NULL) && (ctxt->error != NULL)) { (ctxt, attr->parent, XML_DTD_ ID_REDEFINED,
2637 xmlErrValidNode
2638 "ID %s already defined\n",
2639 value, NULL, NULL);
2640 }
lxml does not currently set ctxt->error, because all errors are collected globally. The check above prevents libxml2 from reporting the error at all in that case, although it would work if the check wasn't there. Meaning, it's really just exactly this error message that does not go through. Thanks for stumbling over it. :)