Best practice for linking Project/Dataset as a different user?

I have a question about best practices for performing actions on behalf of another user, specifically linking a new Dataset to an existing Project, using the Python API.

Here is the scenario: I need to, as Admin, move images owned by User X to a newly created Dataset (owned by User X), that will be linked to an existing Project (owned by User X).

The approach that I have used in the past was to use conn.SERVICE_OPTS for this sort of thing, but I am currently running into permissions errors (can follow up with those errors if this is indeed the best approach).

One way that I know this works is to use conn.suConn to create a new connection as User X – but is this a good approach?

I also notice that there are methods conn.setUserID and conn.setGroupForSession. Would these methods be useful here?

Lots of folks are away at the moment, but:

  • setUserId doesn’t seem to have (m)any uses. I’d avoid.
  • suConn is used in saveAs and linkAnnotation and seems to match the CLI --sudo process.
  • Can you share how SERVICE_OPTS is being used and how it’s failing?

~J.

Okay I’ll give you an overview of what I am doing…actual working version of code is here: https://github.com/TheJacksonLaboratory/jax-omeroutils/blob/8967081d1f174ef1abfc0c540e2314d9ce124d36/sync_with_jaxlims.py

  1. Creating BlitzGateway connection as admin user
  2. Use SERVICE_OPTS to set Group and User:
    conn.SERVICE_OPTS.setOmeroGroup(group_id)
    conn.SERVICE_OPTS.setOmeroUser(user_id)
  3. Grab metadata (a dict) along with filename, Project name, Dataset name from an external file
  4. Look for first Project that matches Project name from metadata file. If none, create (this works)
  5. Look for first Dataset that matches Dataset name and is linked to the above Project. If none, create (this works)
  6. Link the Dataset to the Project, if a new Dataset is created (this fails)
  7. Link images with imported filename to the Dataset (not making it that far yet).

Error message comes when I try to link. The code to link is:

link = ProjectDatasetLinkI()
link.setParent(ProjectI(project_id, False))
link.setChild(DatasetI(dataset.getId(), False))
conn.getUpdateService().saveObject(link)

I need to repeat the problem to produce the exact error, but it amounts to something like I can’t read the dataset due to permissions. I’ll follow up with the exact error shortly

Here is the error:

error
WARNING:omero.gateway:SecurityViolation on <class 'omero.gateway.OmeroGatewaySafeCallWrapper'> to <42105028-fa47-4887-bb98-dd5426dd5112omero.api.IUpdate> saveObject((object #0 (::omero::model::ProjectDatasetLink)
{
    _id = <nil>
    _details = object #1 (::omero::model::Details)
    {
        _owner = <nil>
        _group = <nil>
        _creationEvent = <nil>
        _updateEvent = <nil>
        _permissions = <nil>
        _externalInfo = <nil>
        _call = {}
        _event = <nil>
    }
    _loaded = True
    _version = <nil>
    _parent = object #2 (::omero::model::Project)
    {
        _id = object #3 (::omero::RLong)
        {
            _val = 415
        }
        _details = <nil>
        _loaded = False
        _version = <nil>
        _datasetLinksSeq = {}
        _datasetLinksLoaded = False
        _datasetLinksCountPerOwner = {}
        _annotationLinksSeq = {}
        _annotationLinksLoaded = False
        _annotationLinksCountPerOwner = {}
        _name = <nil>
        _description = <nil>
    }
    _child = object #4 (::omero::model::Dataset)
    {
        _id = object #5 (::omero::RLong)
        {
            _val = 702
        }
        _details = <nil>
        _loaded = False
        _version = <nil>
        _projectLinksSeq = {}
        _projectLinksLoaded = False
        _projectLinksCountPerOwner = {}
        _imageLinksSeq = {}
        _imageLinksLoaded = False
        _imageLinksCountPerOwner = {}
        _annotationLinksSeq = {}
        _annotationLinksLoaded = False
        _annotationLinksCountPerOwner = {}
        _name = <nil>
        _description = <nil>
    }
},), {})
Traceback (most recent call last):
  File "/home/svc-omerodata/omerosubvenv/lib64/python3.6/site-packages/omero/gateway/__init__.py", line 4793, in __call__
    return self.f(*args, **kwargs)
  File "/home/svc-omerodata/omerosubvenv/lib64/python3.6/site-packages/omero_api_IUpdate_ice.py", line 145, in saveObject
    return _M_omero.api.IUpdate._op_saveObject.invoke(self, ((obj, ), _ctx))
omero.SecurityViolation: exception ::omero::SecurityViolation
{
    serverStackTrace = ome.conditions.SecurityViolation: Cannot read ome.model.containers.Dataset:Id_702
	at ome.security.basic.BasicACLVoter.throwLoadViolation(BasicACLVoter.java:300)
	at ome.security.CompositeACLVoter.throwLoadViolation(CompositeACLVoter.java:92)
	at ome.security.ACLEventListener.onPostLoad(ACLEventListener.java:102)
	at org.hibernate.engine.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:250)
	at org.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:982)
	at org.hibernate.loader.Loader.doQuery(Loader.java:857)
	at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:274)
	at org.hibernate.loader.Loader.loadEntity(Loader.java:2037)
	at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:86)
	at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:76)
	at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:3294)
	at org.hibernate.event.def.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:496)
	at org.hibernate.event.def.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:477)
	at org.hibernate.event.def.DefaultLoadEventListener.load(DefaultLoadEventListener.java:227)
	at org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:147)
	at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:1090)
	at org.hibernate.impl.SessionImpl.immediateLoad(SessionImpl.java:1026)
	at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:176)
	at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:215)
	at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)
	at ome.model.containers.Dataset_$$_jvste90_a1.getDetails(Dataset_$$_jvste90_a1.java)
	at ome.security.basic.OmeroInterceptor.evaluateLinkages(OmeroInterceptor.java:542)
	at ome.security.basic.OmeroInterceptor.onSave(OmeroInterceptor.java:184)
	at org.hibernate.event.def.AbstractSaveEventListener.substituteValuesIfNecessary(AbstractSaveEventListener.java:413)
	at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:292)
	at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:203)
	at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:143)
	at org.hibernate.event.def.DefaultMergeEventListener.saveTransientEntity(DefaultMergeEventListener.java:415)
	at org.hibernate.event.def.DefaultMergeEventListener.mergeTransientEntity(DefaultMergeEventListener.java:341)
	at org.hibernate.event.def.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:303)
	at org.springframework.orm.hibernate3.support.IdTransferringMergeEventListener.entityIsTransient(IdTransferringMergeEventListener.java:62)
	at ome.security.basic.MergeEventListener.entityIsTransient(MergeEventListener.java:154)
	at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:258)
	at ome.security.basic.MergeEventListener.onMerge(MergeEventListener.java:87)
	at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:84)
	at ome.security.basic.MergeEventListener.onMerge(MergeEventListener.java:73)
	at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:867)
	at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:851)
	at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:855)
	at ome.logic.UpdateImpl.internalMerge(UpdateImpl.java:313)
	at ome.logic.UpdateImpl$1.run(UpdateImpl.java:128)
	at ome.logic.UpdateImpl$1.run(UpdateImpl.java:125)
	at ome.logic.UpdateImpl.doAction(UpdateImpl.java:357)
	at ome.logic.UpdateImpl.doAction(UpdateImpl.java:349)
	at ome.logic.UpdateImpl.saveObject(UpdateImpl.java:125)
	at jdk.internal.reflect.GeneratedMethodAccessor446.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
	at ome.security.basic.EventHandler.invoke(EventHandler.java:154)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.orm.hibernate3.HibernateInterceptor.invoke(HibernateInterceptor.java:119)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282)
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at ome.tools.hibernate.ProxyCleanupFilter$Interceptor.invoke(ProxyCleanupFilter.java:249)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at ome.services.util.ServiceHandler.invoke(ServiceHandler.java:121)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
	at com.sun.proxy.$Proxy102.saveObject(Unknown Source)
	at jdk.internal.reflect.GeneratedMethodAccessor446.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
	at ome.security.basic.BasicSecurityWiring.invoke(BasicSecurityWiring.java:93)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at ome.services.blitz.fire.AopContextInitializer.invoke(AopContextInitializer.java:43)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
	at com.sun.proxy.$Proxy102.saveObject(Unknown Source)
	at jdk.internal.reflect.GeneratedMethodAccessor650.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at ome.services.blitz.util.IceMethodInvoker.invoke(IceMethodInvoker.java:172)
	at ome.services.throttling.Callback.run(Callback.java:56)
	at ome.services.throttling.InThreadThrottlingStrategy.callInvokerOnRawArgs(InThreadThrottlingStrategy.java:56)
	at ome.services.blitz.impl.AbstractAmdServant.callInvokerOnRawArgs(AbstractAmdServant.java:140)
	at ome.services.blitz.impl.UpdateI.saveObject_async(UpdateI.java:79)
	at jdk.internal.reflect.GeneratedMethodAccessor649.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
	at omero.cmd.CallContext.invoke(CallContext.java:85)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
	at com.sun.proxy.$Proxy103.saveObject_async(Unknown Source)
	at omero.api._IUpdateTie.saveObject_async(_IUpdateTie.java:110)
	at omero.api._IUpdateDisp.___saveObject(_IUpdateDisp.java:179)
	at omero.api._IUpdateDisp.__dispatch(_IUpdateDisp.java:434)
	at IceInternal.Incoming.invoke(Incoming.java:221)
	at Ice.ConnectionI.invokeAll(ConnectionI.java:2536)
	at Ice.ConnectionI.dispatch(ConnectionI.java:1145)
	at Ice.ConnectionI.message(ConnectionI.java:1056)
	at IceInternal.ThreadPool.run(ThreadPool.java:395)
	at IceInternal.ThreadPool.access$300(ThreadPool.java:12)
	at IceInternal.ThreadPool$EventHandlerThread.run(ThreadPool.java:832)
	at java.base/java.lang.Thread.run(Thread.java:834)

    serverExceptionClass = ome.conditions.SecurityViolation
    message = Cannot read ome.model.containers.Dataset:Id_702
}
---------------------------------------------------------------------------
SecurityViolation                         Traceback (most recent call last)
<ipython-input-13-49ea1d013d9d> in <module>
----> 1 ezomero.post_dataset(conn, "test_this", project_id=415)

~/jax-omeroutils/jax_omeroutils/ezomero.py in post_dataset(conn, dataset_name, project_id, description)
     58         link.setParent(ProjectI(project_id, False))
     59         link.setChild(DatasetI(dataset.getId(), False))
---> 60         conn.getUpdateService().saveObject(link)
     61 
     62     return dataset.getId()

~/omerosubvenv/lib64/python3.6/site-packages/omero/gateway/__init__.py in __call__(self, *args, **kwargs)
   4794         except Exception as e:
   4795             self.debug(e.__class__.__name__, args, kwargs)
-> 4796             return self.handle_exception(e, *args, **kwargs)
   4797 
   4798 # Extension point for API users who want to customise the semantics of

~/omerosubvenv/lib64/python3.6/site-packages/omero/gateway/__init__.py in __call__(self, *args, **kwargs)
   4791     def __call__(self, *args, **kwargs):
   4792         try:
-> 4793             return self.f(*args, **kwargs)
   4794         except Exception as e:
   4795             self.debug(e.__class__.__name__, args, kwargs)

~/omerosubvenv/lib64/python3.6/site-packages/omero_api_IUpdate_ice.py in saveObject(self, obj, _ctx)
    143 
    144         def saveObject(self, obj, _ctx=None):
--> 145             return _M_omero.api.IUpdate._op_saveObject.invoke(self, ((obj, ), _ctx))
    146 
    147         def begin_saveObject(self, obj, _response=None, _ex=None, _sent=None, _ctx=None):

SecurityViolation: exception ::omero::SecurityViolation
{
    serverStackTrace = ome.conditions.SecurityViolation: Cannot read ome.model.containers.Dataset:Id_702
	at ome.security.basic.BasicACLVoter.throwLoadViolation(BasicACLVoter.java:300)
	at ome.security.CompositeACLVoter.throwLoadViolation(CompositeACLVoter.java:92)
	at ome.security.ACLEventListener.onPostLoad(ACLEventListener.java:102)
	at org.hibernate.engine.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:250)
	at org.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:982)
	at org.hibernate.loader.Loader.doQuery(Loader.java:857)
	at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:274)
	at org.hibernate.loader.Loader.loadEntity(Loader.java:2037)
	at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:86)
	at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:76)
	at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:3294)
	at org.hibernate.event.def.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:496)
	at org.hibernate.event.def.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:477)
	at org.hibernate.event.def.DefaultLoadEventListener.load(DefaultLoadEventListener.java:227)
	at org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:147)
	at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:1090)
	at org.hibernate.impl.SessionImpl.immediateLoad(SessionImpl.java:1026)
	at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:176)
	at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:215)
	at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)
	at ome.model.containers.Dataset_$$_jvste90_a1.getDetails(Dataset_$$_jvste90_a1.java)
	at ome.security.basic.OmeroInterceptor.evaluateLinkages(OmeroInterceptor.java:542)
	at ome.security.basic.OmeroInterceptor.onSave(OmeroInterceptor.java:184)
	at org.hibernate.event.def.AbstractSaveEventListener.substituteValuesIfNecessary(AbstractSaveEventListener.java:413)
	at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:292)
	at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:203)
	at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:143)
	at org.hibernate.event.def.DefaultMergeEventListener.saveTransientEntity(DefaultMergeEventListener.java:415)
	at org.hibernate.event.def.DefaultMergeEventListener.mergeTransientEntity(DefaultMergeEventListener.java:341)
	at org.hibernate.event.def.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:303)
	at org.springframework.orm.hibernate3.support.IdTransferringMergeEventListener.entityIsTransient(IdTransferringMergeEventListener.java:62)
	at ome.security.basic.MergeEventListener.entityIsTransient(MergeEventListener.java:154)
	at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:258)
	at ome.security.basic.MergeEventListener.onMerge(MergeEventListener.java:87)
	at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:84)
	at ome.security.basic.MergeEventListener.onMerge(MergeEventListener.java:73)
	at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:867)
	at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:851)
	at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:855)
	at ome.logic.UpdateImpl.internalMerge(UpdateImpl.java:313)
	at ome.logic.UpdateImpl$1.run(UpdateImpl.java:128)
	at ome.logic.UpdateImpl$1.run(UpdateImpl.java:125)
	at ome.logic.UpdateImpl.doAction(UpdateImpl.java:357)
	at ome.logic.UpdateImpl.doAction(UpdateImpl.java:349)
	at ome.logic.UpdateImpl.saveObject(UpdateImpl.java:125)
	at jdk.internal.reflect.GeneratedMethodAccessor446.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
	at ome.security.basic.EventHandler.invoke(EventHandler.java:154)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.orm.hibernate3.HibernateInterceptor.invoke(HibernateInterceptor.java:119)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282)
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at ome.tools.hibernate.ProxyCleanupFilter$Interceptor.invoke(ProxyCleanupFilter.java:249)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at ome.services.util.ServiceHandler.invoke(ServiceHandler.java:121)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
	at com.sun.proxy.$Proxy102.saveObject(Unknown Source)
	at jdk.internal.reflect.GeneratedMethodAccessor446.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
	at ome.security.basic.BasicSecurityWiring.invoke(BasicSecurityWiring.java:93)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at ome.services.blitz.fire.AopContextInitializer.invoke(AopContextInitializer.java:43)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
	at com.sun.proxy.$Proxy102.saveObject(Unknown Source)
	at jdk.internal.reflect.GeneratedMethodAccessor650.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at ome.services.blitz.util.IceMethodInvoker.invoke(IceMethodInvoker.java:172)
	at ome.services.throttling.Callback.run(Callback.java:56)
	at ome.services.throttling.InThreadThrottlingStrategy.callInvokerOnRawArgs(InThreadThrottlingStrategy.java:56)
	at ome.services.blitz.impl.AbstractAmdServant.callInvokerOnRawArgs(AbstractAmdServant.java:140)
	at ome.services.blitz.impl.UpdateI.saveObject_async(UpdateI.java:79)
	at jdk.internal.reflect.GeneratedMethodAccessor649.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
	at omero.cmd.CallContext.invoke(CallContext.java:85)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
	at com.sun.proxy.$Proxy103.saveObject_async(Unknown Source)
	at omero.api._IUpdateTie.saveObject_async(_IUpdateTie.java:110)
	at omero.api._IUpdateDisp.___saveObject(_IUpdateDisp.java:179)
	at omero.api._IUpdateDisp.__dispatch(_IUpdateDisp.java:434)
	at IceInternal.Incoming.invoke(Incoming.java:221)
	at Ice.ConnectionI.invokeAll(ConnectionI.java:2536)
	at Ice.ConnectionI.dispatch(ConnectionI.java:1145)
	at Ice.ConnectionI.message(ConnectionI.java:1056)
	at IceInternal.ThreadPool.run(ThreadPool.java:395)
	at IceInternal.ThreadPool.access$300(ThreadPool.java:12)
	at IceInternal.ThreadPool$EventHandlerThread.run(ThreadPool.java:832)
	at java.base/java.lang.Thread.run(Thread.java:834)

    serverExceptionClass = ome.conditions.SecurityViolation
    message = Cannot read ome.model.containers.Dataset:Id_702
}

And the group of Dataset:Id_702 is definitely what you passed to setOmeroGroup? If so, then I’m a bit at a loss. @will-moore may have more insight on his return. In the meantime, can you give suConn a try? ~J

@mellertd Possibly https://github.com/ome/omero-web/issues/182 is of some relevance here. Basically, what you are trying to achieve using CLI or your app, is our desired behaviour in the webclient. Definitely @will-moore has an idea how to achieve this in OMERO.web codebase, as he was discussing the https://github.com/ome/omero-web/issues/182 with us already.
In your original comment, I was wondering about the usage of the word “move”. Does that mean that the images are origianlly in a different group then the dataset and you are moving the images not only into the dataset, but also between OMERO groups ? If moving data between groups using OMERO.web UI, you get the behaviour you desire for free - it just works like that if you are an admin. See https://omero-guides.readthedocs.io/projects/introduction/en/latest/data-management.html?highlight=move#move-data-between-groups-administrators

@joshmoore suConn definitely works, I just wanted to avoid creating a new connection for reasons that aren’t even clear to me (SERVICE_OPTS just seemed like the way I should be doing it). I can easily switch over to using suConn.

@pwalczysko when I used the word “move” I meant “link”. I want to link orphaned images to a dataset, but if the dataset doesn’t exist in the target project, I need to create it. So there are two levels of linking I need to do in certain scenarios, 1) link Dataset to Project and 2) link Images to Dataset. I was getting stuck at the first part, because of the aforementioned permissions issues.

Update:

I got this to work with SERVICE_OPTS. My problem was I needed to pass those as a parameter to the update service:

link = ProjectDatasetLinkI()
link.setParent(ProjectI(project_id, False))
link.setChild(DatasetI(dataset.getId(), False))
conn.getUpdateService().saveObject(link, conn.SERVICE_OPTS)

But now I am getting an entirely new error. This one is weird because there doesn’t seem to be anything wrong with the code per se, if I run it again, it will proceed through the image that raised an exception before, possibly make it through a few more images, then raise the same exception on a different image.

The exception:

exception
WARNING:omero.gateway:ValidationException on <class 'omero.gateway.OmeroGatewaySafeCallWrapper'> to <5e282650-5b17-4906-93b9-76ea213823c1
omero.api.IUpdate> saveObject((object #0 (::omero::model::DatasetImageLink)
{
    _id = <nil>
    _details = object #1 (::omero::model::Details)
    {
        _owner = <nil>
        _group = <nil>
        _creationEvent = <nil>
        _updateEvent = <nil>
        _permissions = <nil>
        _externalInfo = <nil>
        _call = {}
        _event = <nil>
    }
    _loaded = True
    _version = <nil>
    _parent = object #2 (::omero::model::Dataset)
    {
        _id = object #3 (::omero::RLong)
        {   
            _val = 1454
        }   
        _details = <nil>
        _loaded = False
        _version = <nil>
        _projectLinksSeq = {}
        _projectLinksLoaded = False
        _projectLinksCountPerOwner = {}
        _imageLinksSeq = {}
        _imageLinksLoaded = False
        _imageLinksCountPerOwner = {}
        _annotationLinksSeq = {}
        _annotationLinksLoaded = False
        _annotationLinksCountPerOwner = {}
        _name = <nil>
        _description = <nil>
    }
    _child = object #4 (::omero::model::Image)
    {
        _id = object #5 (::omero::RLong)
        {   
            _val = 26605
        }   
        _details = <nil>
        _loaded = False
        _version = <nil>
        _series = <nil>
        _acquisitionDate = <nil>
        _archived = <nil>
        _partial = <nil>
        _format = <nil>
        _imagingEnvironment = <nil>
        _objectiveSettings = <nil>
        _instrument = <nil>
        _stageLabel = <nil>
        _experiment = <nil>
        _pixelsSeq = {}
        _pixelsLoaded = False
        _wellSamplesSeq = {}
        _wellSamplesLoaded = False
        _roisSeq = {}
        _roisLoaded = False
        _datasetLinksSeq = {}
        _datasetLinksLoaded = False
        _datasetLinksCountPerOwner = {}
        _folderLinksSeq = {}
        _folderLinksLoaded = False
        _folderLinksCountPerOwner = {}
        _fileset = <nil>
        _annotationLinksSeq = {}
        _annotationLinksLoaded = False
        _annotationLinksCountPerOwner = {}
        _name = <nil>
        _description = <nil>
    }
}, <ServiceOptsDict: {'omero.client.uuid': '5e282650-5b17-4906-93b9-76ea213823c1', 'omero.session.uuid': '9053c9a9-2bb0-46c2-844e-9b044d8b9797', 'omero.group': '153', 'omero.user': '205'}>), {})
Traceback (most recent call last):
  File "/home/svc-omerodata/omerosubvenv/lib64/python3.6/site-packages/omero/gateway/__init__.py", line 4793, in __call__
    return self.f(*args, **kwargs)
  File "/home/svc-omerodata/omerosubvenv/lib64/python3.6/site-packages/omero_api_IUpdate_ice.py", line 145, in saveObject
    return _M_omero.api.IUpdate._op_saveObject.invoke(self, ((obj, ), _ctx))
omero.ValidationException: exception ::omero::ValidationException
{
    serverStackTrace = ome.conditions.ValidationException: could not insert: [ome.model.containers.DatasetImageLink]; SQL [insert into datasetimagelink (child, creation_id, external_id, group_id, owner_id, permissions, update_id, parent, version, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)]; constraint [datasetimagelink_parent_child_owner_id_key]; nested exception is org.hibernate.exception.ConstraintViolationException: could not insert: [ome.model.containers.DatasetImageLink]
        at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:660)
        at org.springframework.orm.hibernate3.HibernateAccessor.convertHibernateAccessException(HibernateAccessor.java:416)
        at org.springframework.orm.hibernate3.HibernateInterceptor.invoke(HibernateInterceptor.java:125)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
        at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282)
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at ome.tools.hibernate.ProxyCleanupFilter$Interceptor.invoke(ProxyCleanupFilter.java:249)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at ome.services.util.ServiceHandler.invoke(ServiceHandler.java:121)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
        at com.sun.proxy.$Proxy99.saveObject(Unknown Source)
        at jdk.internal.reflect.GeneratedMethodAccessor443.invoke(Unknown Source)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
        at ome.security.basic.BasicSecurityWiring.invoke(BasicSecurityWiring.java:93)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at ome.services.blitz.fire.AopContextInitializer.invoke(AopContextInitializer.java:43)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
        at com.sun.proxy.$Proxy99.saveObject(Unknown Source)
        at jdk.internal.reflect.GeneratedMethodAccessor478.invoke(Unknown Source)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at ome.services.blitz.util.IceMethodInvoker.invoke(IceMethodInvoker.java:172)
        at ome.services.throttling.Callback.run(Callback.java:56)
        at ome.services.throttling.InThreadThrottlingStrategy.callInvokerOnRawArgs(InThreadThrottlingStrategy.java:56)
        at ome.services.blitz.impl.AbstractAmdServant.callInvokerOnRawArgs(AbstractAmdServant.java:140)
        at ome.services.blitz.impl.UpdateI.saveObject_async(UpdateI.java:79)
        at jdk.internal.reflect.GeneratedMethodAccessor477.invoke(Unknown Source)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at ome.services.blitz.util.IceMethodInvoker.invoke(IceMethodInvoker.java:172)
        at ome.services.throttling.Callback.run(Callback.java:56)
        at ome.services.throttling.InThreadThrottlingStrategy.callInvokerOnRawArgs(InThreadThrottlingStrategy.java:56)
        at ome.services.blitz.impl.AbstractAmdServant.callInvokerOnRawArgs(AbstractAmdServant.java:140)
        at ome.services.blitz.impl.UpdateI.saveObject_async(UpdateI.java:79)
        at jdk.internal.reflect.GeneratedMethodAccessor477.invoke(Unknown Source)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
        at omero.cmd.CallContext.invoke(CallContext.java:85)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
        at com.sun.proxy.$Proxy100.saveObject_async(Unknown Source)
        at omero.api._IUpdateTie.saveObject_async(_IUpdateTie.java:110)
        at omero.api._IUpdateDisp.___saveObject(_IUpdateDisp.java:179)
        at omero.api._IUpdateDisp.__dispatch(_IUpdateDisp.java:434)
        at IceInternal.Incoming.invoke(Incoming.java:221)
        at Ice.ConnectionI.invokeAll(ConnectionI.java:2536)
        at Ice.ConnectionI.dispatch(ConnectionI.java:1145)
        at Ice.ConnectionI.message(ConnectionI.java:1056)
        at IceInternal.ThreadPool.run(ThreadPool.java:395)
        at IceInternal.ThreadPool.access$300(ThreadPool.java:12)
        at IceInternal.ThreadPool$EventHandlerThread.run(ThreadPool.java:832)
        at java.base/java.lang.Thread.run(Thread.java:834)

    serverExceptionClass = ome.conditions.ValidationException
    message = could not insert: [ome.model.containers.DatasetImageLink]; SQL [insert into datasetimagelink (child, creation_id, external_id, group_id, owner_id, permissions, update_id, parent, version, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)]; constraint [datasetimagelink_parent_child_owner_id_key]; nested exception is org.hibernate.exception.ConstraintViolationException: could not insert: [ome.model.containers.DatasetImageLink]
}
Traceback (most recent call last):
  File "sync_with_jaxlims.py", line 129, in <module>
    main(args.md, args.user, args.group, args.sudo, args.server, args.port)
  File "sync_with_jaxlims.py", line 54, in main
    link_images_to_dataset(conn, image_ids, dataset_id)
  File "sync_with_jaxlims.py", line 99, in link_images_to_dataset
    conn.getUpdateService().saveObject(link, conn.SERVICE_OPTS)
  File "/home/svc-omerodata/omerosubvenv/lib64/python3.6/site-packages/omero/gateway/__init__.py", line 4796, in __call__
    return self.handle_exception(e, *args, **kwargs)
  File "/home/svc-omerodata/omerosubvenv/lib64/python3.6/site-packages/omero/gateway/__init__.py", line 4793, in __call__
    return self.f(*args, **kwargs)
  File "/home/svc-omerodata/omerosubvenv/lib64/python3.6/site-packages/omero_api_IUpdate_ice.py", line 145, in saveObject
    return _M_omero.api.IUpdate._op_saveObject.invoke(self, ((obj, ), _ctx))
omero.ValidationException: exception ::omero::ValidationException
{
    serverStackTrace = ome.conditions.ValidationException: could not insert: [ome.model.containers.DatasetImageLink]; SQL [insert into datasetimagelink (child, creation_id, external_id, group_id, owner_id, permissions, update_id, parent, version, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)]; constraint [datasetimagelink_parent_child_owner_id_key]; nested exception is org.hibernate.exception.ConstraintViolationException: could not insert: [ome.model.containers.DatasetImageLink]
        at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:660)
        at org.springframework.orm.hibernate3.HibernateAccessor.convertHibernateAccessException(HibernateAccessor.java:416)
        at org.springframework.orm.hibernate3.HibernateInterceptor.invoke(HibernateInterceptor.java:125)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
        at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282)
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at ome.tools.hibernate.ProxyCleanupFilter$Interceptor.invoke(ProxyCleanupFilter.java:249)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at ome.services.util.ServiceHandler.invoke(ServiceHandler.java:121)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
        at com.sun.proxy.$Proxy99.saveObject(Unknown Source)
        at jdk.internal.reflect.GeneratedMethodAccessor443.invoke(Unknown Source)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
        at ome.security.basic.BasicSecurityWiring.invoke(BasicSecurityWiring.java:93)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at ome.services.blitz.fire.AopContextInitializer.invoke(AopContextInitializer.java:43)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
        at com.sun.proxy.$Proxy99.saveObject(Unknown Source)
        at jdk.internal.reflect.GeneratedMethodAccessor478.invoke(Unknown Source)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at ome.services.blitz.util.IceMethodInvoker.invoke(IceMethodInvoker.java:172)
        at ome.services.throttling.Callback.run(Callback.java:56)
        at ome.services.throttling.InThreadThrottlingStrategy.callInvokerOnRawArgs(InThreadThrottlingStrategy.java:56)
        at ome.services.blitz.impl.AbstractAmdServant.callInvokerOnRawArgs(AbstractAmdServant.java:140)
        at ome.services.blitz.impl.UpdateI.saveObject_async(UpdateI.java:79)
        at jdk.internal.reflect.GeneratedMethodAccessor477.invoke(Unknown Source)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
        at omero.cmd.CallContext.invoke(CallContext.java:85)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
        at com.sun.proxy.$Proxy100.saveObject_async(Unknown Source)
        at omero.api._IUpdateTie.saveObject_async(_IUpdateTie.java:110)
        at omero.api._IUpdateDisp.___saveObject(_IUpdateDisp.java:179)
        at omero.api._IUpdateDisp.__dispatch(_IUpdateDisp.java:434)
        at IceInternal.Incoming.invoke(Incoming.java:221)
        at Ice.ConnectionI.invokeAll(ConnectionI.java:2536)
        at Ice.ConnectionI.dispatch(ConnectionI.java:1145)
        at Ice.ConnectionI.message(ConnectionI.java:1056)
        at IceInternal.ThreadPool.run(ThreadPool.java:395)
        at IceInternal.ThreadPool.access$300(ThreadPool.java:12)
        at IceInternal.ThreadPool$EventHandlerThread.run(ThreadPool.java:832)
        at java.base/java.lang.Thread.run(Thread.java:834)

    serverExceptionClass = ome.conditions.ValidationException
    message = could not insert: [ome.model.containers.DatasetImageLink]; SQL [insert into datasetimagelink (child, creation_id, external_id, group_id, owner_id, permissions, update_id, parent, version, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)]; constraint [datasetimagelink_parent_child_owner_id_key]; nested exception is org.hibernate.exception.ConstraintViolationException: could not insert: [ome.model.containers.DatasetImageLink]
}

Minor follow-up on this error:

  1. I get the same exception whether I use SERVICE_OPTS or suConn.

  2. While the exception does cause an exit from the script, the image(s) linking that is throwing the exception actually does happen, as confirmed in OMERO.web.

Any thought on what is going on here?

Hi,

The ValidationException is probably due to the Project-Dataset link already existing, which is why it only fails on some objects where a link already exists. In OMERO, you can’t create duplicate links between the same 2 objects.

You probably also want to ensure that the link belongs to user-X, because if the link belongs to Admin, then user-X won’t be able to delete it in future.

Just need to add this before saving the link:

link.details.owner = omero.model.ExperimenterI(ownerId, False)

Will

The exception was due to dataset-image links already existing. No OMERO issue at all, but a problem with how I was dealing with incoming data. That was a tough one to find, but your guess was essentially correct. Thanks @will-moore!

1 Like