{"record":{"id":"75816fa0f83c5699","repo":"java-native-access/jna","slug":"comobject-must-define-a-value-for-either-clsid-or-progid","errorCode":null,"errorMessage":"ComObject must define a value for either clsId or progId","messagePattern":"ComObject must define a value for either clsId or progId","errorType":"exception","errorClass":"com.sun.jna.platform.win32.COM.COMException","httpStatus":null,"severity":"error","filePath":"contrib/platform/src/com/sun/jna/platform/win32/COM/util/ObjectFactory.java","lineNumber":168,"sourceCode":"        return t;\n    }\n\n    GUID discoverClsId(ComObject annotation) {\n        assert COMUtils.comIsInitialized() : \"COM not initialized\";\n\n        String clsIdStr = annotation.clsId();\n        final String progIdStr = annotation.progId();\n        if (null != clsIdStr && !clsIdStr.isEmpty()) {\n            return new CLSID(clsIdStr);\n        } else if (null != progIdStr && !progIdStr.isEmpty()) {\n            final CLSID.ByReference rclsid = new CLSID.ByReference();\n\n            WinNT.HRESULT hr = Ole32.INSTANCE.CLSIDFromProgID(progIdStr, rclsid);\n\n            COMUtils.checkRC(hr);\n            return rclsid;\n        } else {\n            throw new COMException(\"ComObject must define a value for either clsId or progId\");\n        }\n    }\n\n    IDispatchCallback createDispatchCallback(Class<?> comEventCallbackInterface, IComEventCallbackListener comEventCallbackListener) {\n        return new CallbackProxy(this, comEventCallbackInterface, comEventCallbackListener);\n    }\n\n    // Proxy object release their COM interface reference latest in the\n    // finalize method, which is run when garbadge collection removes the\n    // object.\n    // When the factory is finished, the referenced objects loose their\n    // environment and can't be used anymore. registeredObjects is used\n    // to dispose interfaces even if garbadge collection has not yet collected\n    // the proxy objects.\n    private final List<WeakReference<ProxyObject>> registeredObjects = new LinkedList<>();\n\n    public void register(ProxyObject proxyObject) {\n        synchronized (this.registeredObjects) {","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/java-native-access/jna/blob/d036ad9781adad4b66693e8fa7098e4ac665e0a3/contrib/platform/src/com/sun/jna/platform/win32/COM/util/ObjectFactory.java#L150-L186","documentation":"ObjectFactory.discoverClsId resolves a GUID from the @ComObject annotation: if clsId is present it is parsed directly, else progId is converted via CLSIDFromProgID. If neither is set, this COMException is thrown. It means the annotation exists but is empty of identifying information.","triggerScenarios":"Declaring @ComObject with neither clsId nor progId attributes; annotation attributes left as empty strings after removing a placeholder; a helper passing a partially populated annotation instance.","commonSituations":"Copying annotation boilerplate and deleting both attribute values; generating interfaces from a tool that left the fields blank; typos in attribute names so neither recognized field is actually set.","solutions":["Set exactly one of @ComObject(clsId=\"{GUID}\") or @ComObject(progId=\"App.Object\")","Prefer progId for readable code, or clsId for precision; verify the value exists on the target machine (progId resolution happens via CLSIDFromProgID)","Validate the clsId GUID format if using clsId"],"exampleFix":"// before\n@ComObject\npublic interface IWorksheet extends IUnknown { ... }\n// after\n@ComObject(clsId = \"{00020820-0000-0000-C000-000000000046}\")\npublic interface IWorksheet extends IUnknown { ... }","handlingStrategy":"validation","validationCode":"ComObject a = iface.getAnnotation(ComObject.class);\nif (a == null || (a.clsId().isEmpty() && a.progId().isEmpty()))\n    throw new IllegalArgumentException(iface.getName() + \" must set clsId or progId\");","typeGuard":null,"tryCatchPattern":"try { T obj = factory.createObject(iface); } catch (COMException e) { if (e.getMessage().contains(\"must define a value\")) { /* set clsId/progId */ } throw e; }","preventionTips":["Always fill exactly one of clsId/progId in @ComObject","Validate GUID format for clsId at startup","Review generated interfaces for blank annotation attributes"],"tags":["java","com","annotation","clsid","progid"],"backgroundTag":"empty-required-field","analyzedSha":"d036ad9781adad4b66693e8fa7098e4ac665e0a3","analyzedAt":"2026-09-12T06:50:59.239Z","contentChangedAt":"2026-09-12T06:50:59.239Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}