Repository navigation
Replace broken links send by ChatGpt #1276
Description
Problem
ChatGpt attempts to answer each question posted in #question and it provides "useful links", which is great.
However, and especially because ChatGpt runs with old models, it sometimes posts dead links. That leads to unecessary user frustration.
For example in this post:
The first and last link are both 404 NOT FOUND.
Proposed Solution
We should write code that either removes those links or at least replaces them, for example by (broken link).
For that, we should add some helper methods to the already existing LinkDetection class and also use one of the already existing methods there:
- Add a method like
CompletableFuture<Boolean> isLinkDead(String url)to it (which usesHttpClient#sendAsyncto check the status. Dont download the full content, just check the status code, it must be 2xx or 3xx. Make sure this runs non-blocking, i.e. with aCompletableFuture. - Add a method like
CompletableFuture<String> replaceDeadLinks(String text, String replacement)that uses above methods and the existingextractLinksmethod to replace all dead links in the given text with the given replacement. SinceisLinkDeadruns async, this will run async as well with all futures combined
Once that is done, use that method for the ChatGpt responses. They are constructed in HelpSystemHelper#145. Ideally we send out the chatgpt response without delay, check the links async and then, when the result for that is available through the future, we edit the existing chatgpt response.
This can be done by adding more actions onto the queue in HelpThreadCreatedListener#createAIResponse. RestAction allows adding something like "and then do this" to it.
If we have trouble with this, we can also try to do the link replacement in a blocking way directly, without any edits. But that as a fallback.
Ideally all the helper methods added are all unit tested properly. For the isLinkDead we can mock the HttpClient, so no actual HTTP requests are send out.
Already done
The utility methods proposed above have all been added and merged with #1366 already. Now we just have to use them in the right place, easy 👌

Activity
tferdous17 commentedon Jul 11, 2025
Would like to take this one on (anax). Can I get assigned?
Zabuzard commentedon Sep 10, 2025
@tferdous17 Any progress? Otherwise we would probably unassign you for now, so someone else could take it 🙂
tferdous17 commentedon Sep 12, 2025
Yeah sorry I got caught up with some stuff IRL the past couple months so I havent been able to put enough time into my TJ Bot ticket. I finished creating the static helper methods that were outlined in the ticket from what I remember but I never got around to the unit testing
I dont mind getting unassigned so someone else can take over and complete the job
Zabuzard commentedon Sep 12, 2025
No worries. Feel free to callback should you want to continue on it👍
barsh404error commentedon Dec 28, 2025
@christolis i will gladly contribute on this, is there anything i can do or just review it and add some changes if i can?
christolis commentedon Dec 28, 2025
Of course! Will assign you now.
Zabuzard commentedon Mar 3, 2026
#1366 has been merged. This simplifies this ticket a lot. Now its just calling one or two existing functions in the right place, done.
barsh404error commentedon Mar 3, 2026
@Zabuzard i might do the response flow if no one assigns to the issue, for now i am happy with what i have done :]
vlaym commentedon Apr 29, 2026
I've opened a PR that implements the fallback approach from the issue description - dead links are replaced before the embed is built, so the user never sees them.
The ideal flow would be: send the ChatGPT response immediately, check links in the background, then edit the already-sent message with clean links. But these two steps use different async mechanisms:
So some work is needed to connect them, and it requires careful error handling - for example, if the link check fails after the message was already sent, the original message should stay untouched.
I went with the simpler option for now to keep the change focused and testable. Though I'd try to implement the async-edit flow if that's the preferred direction.