java-native-access/jna · error · com.sun.jna.platform.win32.COM.COMException
createObject: Interface must define a value for either…
Error message
createObject: Interface must define a value for either clsId or progId via the ComInterface annotation
What it means
ObjectFactory.createObject instantiates a COM object for the given interface; it requires the interface to carry a @ComObject annotation that supplies a clsId or progId. If the annotation is missing entirely, this COMException is thrown. Without the annotation the factory has no way to know which COM class to CoCreateInstance.
Solutions
- Annotate the interface with @ComObject(clsId="{GUID}") or @ComObject(progId="Excel.Application")
- Confirm the annotation is com.sun.jna.platform.win32.COM.util.annotation.ComObject (wrong import silently fails lookup)
- Rebuild and verify the class file passed to createObject actually retains the annotation
Example fix
// before
public interface IApplication extends IComObject { ... }
factory.createObject(IApplication.class);
// after
@ComObject(progId = "Excel.Application")
public interface IApplication extends IComObject { ... }
factory.createObject(IApplication.class); Defensive patterns
Strategy: validation
Validate before calling
if (iface.getAnnotation(ComObject.class) == null)
throw new IllegalArgumentException(iface.getName() + " requires @ComObject(clsId|progId)"); Try / catch
try { T obj = factory.createObject(iface); } catch (COMException e) { if (e.getMessage().contains("clsId or progId")) { /* add annotation */ } throw e; } Prevention
- Annotate every creatable COM interface with @ComObject
- Verify the annotation import is the JNA one
- Add a reflection-based test asserting required annotations
When it happens
Trigger: Calling factory.createObject(MyComInterface.class) where MyComInterface has no @ComObject annotation; interface defined against a different annotation (e.g. only @ComInterface); annotation removed in a refactor.
Common situations: Hand-writing the Java COM interface and forgetting @ComObject; migrating code that previously used raw GUIDs/IDispatch to the annotation-based util API; copy-pasting an event-callback interface (which uses @ComInterface) where a creatable class interface is needed.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- ComObject must define a value for either clsId or progId
- advise: Interface must define a value for either iid via…
- ComInterface must define a value for iid
- Property Accessor name must start with 'get', or set the…
- Property Mutator name must start with 'set', or set the…
AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12).
Data as JSON: /api/errors/281a62adb44d3013.
Report an issue: GitHub.
Appendix: source
Thrown at contrib/platform/src/com/sun/jna/platform/win32/COM/util/ObjectFactory.java:108
public <T> T createProxy(Class<T> comInterface, IDispatch dispatch) {
assert COMUtils.comIsInitialized() : "COM not initialized";
ProxyObject jop = new ProxyObject(comInterface, dispatch, this);
Object proxy = Proxy.newProxyInstance(comInterface.getClassLoader(), new Class<?>[]{comInterface}, jop);
T result = comInterface.cast(proxy);
return result;
}
/**
* Creates a new COM object (CoCreateInstance) for the given progId and
* returns a ProxyObject for the given interface.
*/
public <T> T createObject(Class<T> comInterface) {
assert COMUtils.comIsInitialized() : "COM not initialized";
ComObject comObectAnnotation = comInterface.getAnnotation(ComObject.class);
if (null == comObectAnnotation) {
throw new COMException(
"createObject: Interface must define a value for either clsId or progId via the ComInterface annotation");
}
final GUID guid = this.discoverClsId(comObectAnnotation);
final PointerByReference ptrDisp = new PointerByReference();
WinNT.HRESULT hr = Ole32.INSTANCE.CoCreateInstance(guid, null,
WTypes.CLSCTX_SERVER, IDispatch.IID_IDISPATCH, ptrDisp);
COMUtils.checkRC(hr);
Dispatch d = new Dispatch(ptrDisp.getValue());
T t = this.createProxy(comInterface, d);
//CoCreateInstance returns a pointer to COM object with a +1 reference count, so we must drop one
//Note: the createProxy adds one
int n = d.Release();
return t;
}
/**View on GitHub (pinned to d036ad9781)