I’m trying to create a system where I will expose to end users the option to run tasks in the background. I want these users to be able to manage their tasks transparently.
This means that I want to use Oban to do that but I don’t want to expose anything related to oban to the end user.
So, for example, if the task finishes successfully, I can just use recorded: true and expose the recorded value to the end user instead of the full job structure.
This works fine for jobs that finished correctly, but not for jobs that failed to run, in these cases, what I tried to do was have an struct defined in a module, instantiate it in the job and return as {:error, struct}.
The issue with this is that Oban will convert this into an Oban.PerformError, and then store just the message value in the errors array of the job table, something like this:
errors: [
%{
"at" => "2026-02-04T23:18:39.876954Z",
"attempt" => 1,
"error" => "** (Oban.PerformError) Core.Workers.ApiCaller failed with {:error, %ErrorReply{http_code: 1, error: \"blobs\"}}"
},
%{
"at" => "2026-02-04T23:18:58.044722Z",
"attempt" => 2,
"error" => "** (Oban.PerformError) Core.Workers.ApiCaller failed with {:error, %ErrorReply{http_code: 1, error: \"blobs\"}}"
},
...
]
I don’t want to show this to the end user since it “exposes” oban, I just want the struct I created as the output.
Is there some way for me to achieve that without having to manage these states in a separated, custom, table?






















