I recently installed Confluence to try it out as a possible replacement for MediaWiki for internal documentation.

However, I ran into a bug. In this post, I explain the bug, the solution, and provide 5 tips on how it could have been avoided. If you follow these tips, you'll help save everyone time.

The Bug

The installation of Confluence went smoothly, but once it was up and running, I ran into this error while testing out the WYSIWYG editor:

Can't revert to last published version

We can't get the last published version of the page at the moment. Give it a few moments then try discarding the draft again.

This error would appear when selecting the "discard all changes" option when editing any page.

My frustration

This was rather frustrating, as it meant there was no easy way to abandon your edits and start from the original document again. For example, when you've messed it up.

I waited 24 hours, restarted the server, and more. No luck. I kept getting the same error message.

Tip 1 - Avoid Misleading Users with Error Messages

Unfortunately, with this bug, the error message didn't really help me to debug it. The wording "at the moment" and "Give it a few moments then try ... again" implies that the problem is transient and will go away if I wait.

The wording is important

The language used in the error message gave me the incorrect impression that something was happening in the background and I just needed to wait for that to complete.

As it turns out, one of the XHR requests was failing (400 Bad Request). This is not something that was going to fix itself.

Add technical information

One solution would be to add this technical information to the error message. However, for non-technical users it would be advisable to hide this detail behind a "more information" link. This also allows them to easily share the technical details with support when they need it.

Security concerns

Sometimes, adding technical details is a security concern. Another solution would be to avoid misleading users by adding extra details. For example, if this error continues to occur or always occurs, you may have a configuration error.

Writing error messages is hard

I understand that error messages are:

  • hard to write
  • reused for multiple causes

However, this makes it more important to try to add more relevant information and to avoid misleading information.

Tip 2 - Always include the Error Message when Writing Publicly

The bug report that relates to this issue, the page that would have put me on the right track to solve the issue, does not contain the error message.

So, during my initial debug searches, I never found the bug report.

People find solutions by searching for error messages

Error messages are a fantastic way to find solutions to problems. Normally, when you run into an error, you simply search for the error message and find lots of solutions.

The error message is often the only common element that all users will encounter, and it is the obvious first search for all users.

So, make sure that when you write publicly about an issue or bug, that you always include the error message that occurs. This way, people will be able to find what you've written about the issue when they encounter the bug.

Tip 3 - Answer Public Questions

When I searched for the error message, I found that others had encountered the same issue. Unfortunately, no-one had posted a solution and it looked like the problem had been around since 2016.

This is bad news. To me, it looked like this was a long-standing issue and the lack of any response didn't give me much hope that I could solve it.

It would have been great to even just get a link to the open bug report, but alas, it is possible that no-one else discovered that – see tip 2.

Frustration leads to uninstalls

The logs contained nothing noteworthy, I rechecked all the documentation, all my configuration, and everything was correct.

At this point, I had flicked off a tweet to Confluence about the issue with no reply and had tried to file a bug report but was denied due to lack of permissions.

I was ready to give up and uninstall. This is the reason to answer your public questions.

Tip 4 - Share Your Findings

In the end, I contacted Atlassian support and was quite impressed by their quick response. While they didn't have an immediate solution, their information gathering questions made me think the reverse proxy may be the problem.

I tested on localhost without the proxy and sure enough, it worked. After further searches, I found the bug report and their rewrite "solution" (it doesn't actually fix the problem), which I quickly implemented.

Hurray, the error message is gone.

A defective solution

Unfortunately, their rewrite is incorrect: it fixes the symptom (the error message) but fails to cure the problem.

The new rewrite sends the request to the wrong URL. Consequently, the XHR request no longer produces a 4XX error, the client-side code thinks all is well and there is no more error. But the problem remains, in fact, it is worse, rather than an error, it saves the changes rather than discard them. That's not good.

I went back to test on localhost again, and sure enough, everything was working fine there. So obviously, the IIS reverse proxy rewrites needed to change, but to what?

I suspect someone knows the answer, but they didn't post it anywhere.

Share everything

Share where you found the solution

If you find a solution and the answer was missing from the earlier places you looked, go back, and add it. You'll help people find the answer faster in the future.

There is nothing more frustrating than searching for a problem, only to find numerous posts with no answer, but lots of people claiming an obvious answer exists and you only need to search for it. This usually makes me think of Fermat's Last Theorem, except there are no space constraints online.

Share what you've learned

Even if you can't find a solution, go back, and share your findings – what you've tried and what you've discovered. Someone else might be able to use that as a head start and ultimately solve the problem.

Share your solution

If you do find a solution to a problem, please share your findings, which is the ultimate point of this post.

Others are bound to run into the same problem and will be very thankful for your solution or even just what you tried.

Tip 5 - Be Altruistic for Yourself

Even if you're not altruistic, think of your future self.

I often find myself running into problems that I've hit before. If a long time has passed, you'll have forgotten the solution and have to start from scratch and debug it all over again.

Finding your own solution is amazing

It truly is a wonderful experience to go looking for a solution to a problem, only to find your own blog article, forum post, or comment. I've had this occur several times in the last 12 months.

It is then that you remember how long it took you to find the solution the first time around and how quick it will be this time, because you've found what you shared last time.

The Solution

I'm using IIS to reverse proxy the requests from a local domain to Confluence. The documentation states that you need 3 rewrite rules. Unfortunately, the first of these rewrite rules is missing a caret.

Instead of matching synchrony/(.*) on the Synchrony HTTP rewrite rule, you need to match ^synchrony/(.*)

This rewrite rule caused the problem as without the caret it caught requests to rest/synchrony/(.*) that should have been handled by the final (.*) rewrite rule.

Here is the complete listing of the corrected rewrite rule section:

        <clear />
        <rule name="Synchrony HTTP" stopProcessing="true">
            <match url="^synchrony/(.*)" />
            <conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
            <action type="Rewrite" url="http://localhost:8091/synchrony/{R:1}" />
        <rule name="Synchrony Web Sockets Reverse Proxy" stopProcessing="true">
            <match url="ws://(.*)" />
            <conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
            <action type="Rewrite" url="ws://localhost:8091/{R:1}" />
        <rule name="Confluence Reverse Proxy" stopProcessing="true">
            <match url="(.*)" />
            <conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
            <action type="Rewrite" url="http://localhost:8090/{R:1}" />