# Automation Professionals' Blob Server Module

**URL:** <https://forum.inductiveautomation.com/t/automation-professionals-blob-server-module/57970>\
**Category:** 3rd Party Modules\
**Tags:** ignition81, ignition83, perspective, database\
**Created:** [April 2, 2022, 7:16pm UTC](https://forum.inductiveautomation.com/t/automation-professionals-blob-server-module/57970 "2022-04-02T19:16:08Z")\
**Posts on this page:** 15\
**Page:** 7

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [January 14, 2026, 3:45pm UTC](https://forum.inductiveautomation.com/t/automation-professionals-blob-server-module/57970/122 "2026-01-14T15:45:42Z")

</div>

Works in my lab VMs with 8.3.2. Are you sure you installed the v8.3 module file on the v8.3 server? (Module files for v8.1 will not work on v8.3--not for anyone's module.)

If you **did** use the right file, please share the wrapper.log content that corresponds to the fault.

---

<div class="post-metadata">

**Author:** ![bwhite](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bwhite/32/7112_2.png) [@bwhite](https://forum.inductiveautomation.com/u/bwhite)\
**Post date:** [January 14, 2026, 5:16pm UTC](https://forum.inductiveautomation.com/t/automation-professionals-blob-server-module/57970/123 "2026-01-14T17:16:00Z")

</div>

```python
com.inductiveautomation.ignition.common.modules.ModuleLoadException: Unable to load hook class "com.automation_pros.blobserve.GatewayHook" for module "com.automation_pros.blobserve".
	at com.inductiveautomation.ignition.gateway.modules.ModuleInstance.loadHook(ModuleInstance.java:632)
	at com.inductiveautomation.ignition.gateway.modules.ModuleInstance.load(ModuleInstance.java:306)
	at com.inductiveautomation.ignition.gateway.modules.ModuleManagerImpl.loadModules(ModuleManagerImpl.java:306)
	at com.inductiveautomation.ignition.gateway.modules.ModuleManagerImpl.init(ModuleManagerImpl.java:162)
	at com.inductiveautomation.ignition.gateway.IgnitionGateway.startupInternal(IgnitionGateway.java:1120)
	at com.inductiveautomation.ignition.gateway.redundancy.RedundancyManagerImpl.startup(RedundancyManagerImpl.java:352)
	at com.inductiveautomation.ignition.gateway.IgnitionGateway.initRedundancy(IgnitionGateway.java:814)
	at com.inductiveautomation.ignition.gateway.IgnitionGateway.lambda$initInternal$1(IgnitionGateway.java:736)
	at com.inductiveautomation.ignition.common.execution.impl.BasicExecutionEngine$ThrowableCatchingRunnable.run(BasicExecutionEngine.java:550)
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
	at java.base/java.util.concurrent.FutureTask.run(Unknown Source)
	at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at java.base/java.lang.Thread.run(Unknown Source)
Caused by: java.lang.ClassNotFoundException: com.automation_pros.blobserve.GatewayHook
	at java.base/java.net.URLClassLoader.findClass(Unknown Source)
	at com.inductiveautomation.ignition.gateway.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:37)
	at com.inductiveautomation.ignition.gateway.modules.ModuleClassLoader.loadClass(ModuleClassLoader.java:104)
	at java.base/java.lang.ClassLoader.loadClass(Unknown Source)
	at com.inductiveautomation.ignition.gateway.modules.ModuleInstance.loadHook(ModuleInstance.java:609)
	at com.inductiveautomation.ignition.gateway.modules.ModuleInstance.load(ModuleInstance.java:306)
	at com.inductiveautomation.ignition.gateway.modules.ModuleManagerImpl.loadModules(ModuleManagerImpl.java:306)
	at com.inductiveautomation.ignition.gateway.modules.ModuleManagerImpl.init(ModuleManagerImpl.java:162)
	at com.inductiveautomation.ignition.gateway.IgnitionGateway.startupInternal(IgnitionGateway.java:1120)
	at com.inductiveautomation.ignition.gateway.redundancy.RedundancyManagerImpl.startup(RedundancyManagerImpl.java:352)
	at com.inductiveautomation.ignition.gateway.IgnitionGateway.initRedundancy(IgnitionGateway.java:814)
	at com.inductiveautomation.ignition.gateway.IgnitionGateway.lambda$initInternal$1(IgnitionGateway.java:736)
	at com.inductiveautomation.ignition.common.execution.impl.BasicExecutionEngine$ThrowableCatchingRunnable.run(BasicExecutionEngine.java:550)
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
	at java.base/java.util.concurrent.FutureTask.run(Unknown Source)
	at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at java.base/java.lang.Thread.run(Unknown Source)

```

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [January 14, 2026, 5:22pm UTC](https://forum.inductiveautomation.com/t/automation-professionals-blob-server-module/57970/124 "2026-01-14T17:22:16Z")

</div>

That means the entire module failed to load. Is there no other relevant message immediately above that?

Does your module file end with `...-v83.modl`?

Also, did your upgrade process insert some `--add-opens=...` additional java options? My v8.3 test VMs have these:

```python
wrapper.java.additional.2=--add-opens=java.base/java.lang=ALL-UNNAMED
wrapper.java.additional.3=--add-opens=java.base/java.io=ALL-UNNAMED
wrapper.java.additional.4=--add-opens=java.base/java.security.cert=ALL-UNNAMED
wrapper.java.additional.5=--add-opens=java.base/java.util=ALL-UNNAMED
wrapper.java.additional.6=--add-opens=java.base/jdk.internal.misc=ALL-UNNAMED

```

---

<div class="post-metadata">

**Author:** ![bwhite](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bwhite/32/7112_2.png) [@bwhite](https://forum.inductiveautomation.com/u/bwhite)\
**Post date:** [January 14, 2026, 5:30pm UTC](https://forum.inductiveautomation.com/t/automation-professionals-blob-server-module/57970/125 "2026-01-14T17:30:57Z")

</div>

# Java Additional Parameters

#wrapper.java.additional.=1-XX:+UseConcMarkSweepGC  
#wrapper.java.additional.2=-XX:+CMSClassUnloadingEnabled  
wrapper.java.additional.3=-Ddata.dir=data  
wrapper.java.additional.4=-Dorg.apache.catalina.loader.WebappClassLoader.ENABLE\_CLEAR\_REFERENCES=false  
#wrapper.java.additional.5=-Xdebug  
#wrapper.java.additional.6=-Xrunjdwp:transport=dt\_socket,server=y,suspend=n,address=8000  
wrapper.java.additional.5=-Dedition=  
wrapper.java.additional.6=--add-opens=java.base/java.lang=ALL-UNNAMED  
wrapper.java.additional.7=--add-opens=java.base/java.security.cert=ALL-UNNAMED  
wrapper.java.additional.8=--add-opens=java.base/java.util=ALL-UNNAMED  
wrapper.java.additional.9=--add-opens=java.base/jdk.internal.misc=ALL-UNNAMED  
wrapper.java.additional.10=--add-opens=java.base/java.io=ALL-UNNAMED

---

<div class="post-metadata">

**Author:** ![bwhite](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bwhite/32/7112_2.png) [@bwhite](https://forum.inductiveautomation.com/u/bwhite)\
**Post date:** [January 14, 2026, 5:32pm UTC](https://forum.inductiveautomation.com/t/automation-professionals-blob-server-module/57970/126 "2026-01-14T17:32:11Z")

</div>

![image](https://us1.discourse-cdn.com/inductiveautomation/optimized/3X/a/a/aacefd0aa2781cd635697009cf25010e07c49c7f_2_690x45.png)

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [January 14, 2026, 5:35pm UTC](https://forum.inductiveautomation.com/t/automation-professionals-blob-server-module/57970/127 "2026-01-14T17:35:24Z")

</div>

Does clicking on the red "Faulted" notice take you to that traceback?

Consider uninstalling my module, restarting the gateway, and re-installing.

(I'm stumped--that error occurs without running **any** of my module's code, so there doesn't appear to be anything I could fix.)

---

<div class="post-metadata">

**Author:** ![bwhite](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bwhite/32/7112_2.png) [@bwhite](https://forum.inductiveautomation.com/u/bwhite)\
**Post date:** [January 14, 2026, 5:42pm UTC](https://forum.inductiveautomation.com/t/automation-professionals-blob-server-module/57970/128 "2026-01-14T17:42:34Z")

</div>

The red faulted does take me to that error. There isn’t anything above that error in the wrapper log that is relevant except that the gateway was restarted. I uninstalled and the restarted the gateway, reinstalled and restarted the gateway again and it still has the error. perhaps the download didn’t go well and i should download again.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [January 14, 2026, 5:46pm UTC](https://forum.inductiveautomation.com/t/automation-professionals-blob-server-module/57970/129 "2026-01-14T17:46:47Z")

</div>

Try checking my module file's signature:

```python
$ sha256sum "Blob Serve-1.1.0.252721936-v83.modl"
88af4eaffebc4fb7235f9f3d093325df8cbc8b2cb91c436557ce6070d819e03a Blob Serve-1.1.0.252721936-v83.modl

```

---

<div class="post-metadata">

**Author:** ![bwhite](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bwhite/32/7112_2.png) [@bwhite](https://forum.inductiveautomation.com/u/bwhite)\
**Post date:** [January 15, 2026, 1:41pm UTC](https://forum.inductiveautomation.com/t/automation-professionals-blob-server-module/57970/130 "2026-01-15T13:41:13Z")

</div>

Phil,

Thanks for the help. IT security was blocking the installation without any popup or notification that it was doing that. I called support and was able to get it installed.

---

<div class="post-metadata">

**Author:** ![rob.claassen](https://avatars.discourse-cdn.com/v4/letter/r/a587f6/32.png) [@rob.claassen](https://forum.inductiveautomation.com/u/rob.claassen)\
**Post date:** [January 23, 2026, 6:24am UTC](https://forum.inductiveautomation.com/t/automation-professionals-blob-server-module/57970/131 "2026-01-23T06:24:58Z")

</div>

Hi Phil,

Appreciate the work on your module, great work. We are trying to build something similar in our Perspective project: we have files stored on our server that we can load as blob content, and want to display the file in the browser. We have created a WebDev endpoint to serve the blob, but we run into authentication issues there. We are using SSO in our project, yet when we try to reach the endpoint in the browser an authentication prompt is still made. This is not workable for us. We are wondering how you present the blob content in the browser without using the webdev module.  
Say we have blob content like this: blob = system.file.readFileAsBytes(file\_path). How do you then display this in the browser?

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [January 23, 2026, 1:27pm UTC](https://forum.inductiveautomation.com/t/automation-professionals-blob-server-module/57970/132 "2026-01-23T13:27:14Z")

</div>

Use the `bytes` dictionary key in the dictionary you return from `doGet()`.

> **[Python Resources​ - Web Dev | Ignition User Manual](https://www.docs.inductiveautomation.com/docs/8.1/ignition-modules/web-dev#python-resources)**
>
> The Web Dev module enables you to directly program against the web server inside the Ignition Gateway. Webpages can be built by hand using a combination of Python programming and static web resources such as images, CSS files, JavaScript files, and...

WebDev doesn't enforce any permissions by default.

If this doesn't help, show your complete WebDev `doGet()` method. (Use the preformatted text style on this forum for code.)

> [@rob.claassen](#):
>
> you present the blob content in the browser without using the webdev module

Any 3rd party module (Java) can add routes or complete servlets to Ignition. My Blob Server adds a servlet.

---

<div class="post-metadata">

**Author:** ![Brian\_Seater](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/brian_seater/32/82110_2.png) [@Brian\_Seater](https://forum.inductiveautomation.com/u/Brian_Seater)\
**Post date:** [March 31, 2026, 5:24pm UTC](https://forum.inductiveautomation.com/t/automation-professionals-blob-server-module/57970/134 "2026-03-31T17:24:28Z")

</div>

Hi Phil,

I’m running into an “issue” with the Blob server and videos. Issue in quotes because it’s working fine, but writing a warning to the Gateway log every time a video is accessed. This is just an annoyance at the log entries, and not impacting functionality.

If I use a text file everything works as expected.

The video is a ~6 MB .webm and it plays fine when accessing it through the Blob server in a browser.

This warning is showing up in the gateway log though:

```python
Unable to handle blob request path /blob/…

	org.eclipse.jetty.io.EofException: null
	at org.eclipse.jetty.io.SocketChannelEndPoint.flush(SocketChannelEndPoint.java:116)
	at org.eclipse.jetty.io.WriteFlusher.flush(WriteFlusher.java:422)
	at org.eclipse.jetty.io.WriteFlusher.completeWrite(WriteFlusher.java:377)
	at org.eclipse.jetty.io.SelectableChannelEndPoint$2.run(SelectableChannelEndPoint.java:67)
	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.runTask(AdaptiveExecutionStrategy.java:421)
	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.consumeTask(AdaptiveExecutionStrategy.java:375)
	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.tryProduce(AdaptiveExecutionStrategy.java:277)
	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.run(AdaptiveExecutionStrategy.java:199)
	at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:411)
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:969)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.doRunJob(QueuedThreadPool.java:1194)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1149)
	at java.base/java.lang.Thread.run(Unknown Source)
	Caused by: java.io.IOException: Broken pipe
	at java.base/sun.nio.ch.FileDispatcherImpl.writev0(Native Method)
	at java.base/sun.nio.ch.SocketDispatcher.writev(Unknown Source)
	at java.base/sun.nio.ch.IOUtil.write(Unknown Source)
	at java.base/sun.nio.ch.IOUtil.write(Unknown Source)
	at java.base/sun.nio.ch.SocketChannelImpl.write(Unknown Source)
	at java.base/java.nio.channels.SocketChannel.write(Unknown Source)
	at org.eclipse.jetty.io.SocketChannelEndPoint.flush(SocketChannelEndPoint.java:110)

```

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [March 31, 2026, 6:08pm UTC](https://forum.inductiveautomation.com/t/automation-professionals-blob-server-module/57970/135 "2026-03-31T18:08:36Z")

</div>

I would think that an artifact of size limits in perspective. Nothing my module can do about that. Also, large blobs do not play nice with NQ caches. Ergo my recommendations for segmenting videos.

---

<div class="post-metadata">

**Author:** ![daniel.soderborg](https://avatars.discourse-cdn.com/v4/letter/d/e5b9ba/32.png) [@daniel.soderborg](https://forum.inductiveautomation.com/u/daniel.soderborg)\
**Post date:** [September 11, 2026, 2:00pm UTC](https://forum.inductiveautomation.com/t/automation-professionals-blob-server-module/57970/136 "2026-09-11T14:00:33Z")

</div>

I'm having the same issue as @rpavlicek that I can't update the pictures using `.refreshBinding()`.

I have also tried using a throw-away parameter `dateExtract(now({session.custom.updateTime}), 'second')` but the problem with this one is that once a minute has passed, it uses the cached images from the last get-request. I could probably change it into `now({session.custom.updateTime})` but then I will just fill the cache with old pictures and you recommended to NOT do this.

I'm doing a "surveillance system" on a production line by taking pictures from IP-cameras using a Gateway Timer Event. Then I present the pictures from the SQL table in a picture component in Perspective which is passed into a Flex repeater to be able to pass the cameraID into the right component.

How would I go about your recommendation to insert rows into the SQL table instead of updating?

Right now my table has a cameraID column and a image\_blob column. My url uses the cameraID as the only parameter. So even if I add a thrid column, named ID which is primary key, my url won't change.  
Do I need to fetch the new ID and pass that into the url instead? Or will it work using the cameraID because the SQL-query is not the same?

Expression binding on image component:

![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/d/b/dbd1c778b206e01490cf3f64629dcc0c8a3ec3a5.png)

Result of SQL Select query:

![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/8/1/81a7c46ffce4aefee4d4a5496713a2bea3ca0716.png)

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [September 11, 2026, 3:12pm UTC](https://forum.inductiveautomation.com/t/automation-professionals-blob-server-module/57970/137 "2026-09-11T15:12:27Z")

</div>

There's no good answer. You are going to abuse the browser's image cache one way other other. Instead of using just the second as the throwaway parameter, consider using the full timestamp milliseconds.

Or add a column for image ID and autoincrement it on insert. Run a timer that prunes old images to clean up the DB.

[Previous page](https://forum.inductiveautomation.com/t/automation-professionals-blob-server-module/57970.md?page=6)
