This question is intended to apply to any OO programming language that supports exception handling; I am using C# for illustrative purposes only.

Exceptions are usually intended to be raised when an problem happens that the code cannot immediately handle, which is then caught in a catch clause in a different location (usually an outer stack frame).

My question is this: are there any legitimate situations where exceptions are not thrown and caught, but simply returned from a method and then passed around as error objects?

This question came up for me because .NET 4's System.IObserver.OnError method suggests just that: exceptions being passed around as error objects.

Let's look at another scenario, validation. Let's say I am following conventional wisdom and that I am therefore distinguishing between an error object type IValidationError and a separate exception type ValidationException that is used to report unexpected errors:

What’s in an exception?

Are there any legitimate situations where exceptions are not thrown and caught, but simply returned from a method and then passed around as error objects?

If it is never thrown then it's not an exception. It is an object derived from an Exception class, though it does not follow the behavior. Calling it an Exception is purely semantics at this point, but I see nothing wrong with not throwing it. From my perspective, not throwing an exception is the exact same thing as an inner-function catching it and preventing it from propagating.

Is it valid for a function to return exception objects?

Absolutely. Here is a short list of examples where this may be appropriate:

An exception factory.

A context object that reports if there was a previous error as a ready to use exception.

A function that keeps a previously caught exception.

A third-party API that creates an exception of an inner type.

Is not throwing it bad?

Throwing an exception is kind of like: "Go to jail. Do not pass Go!" in the board game Monopoly. It tells a compiler to jump over all source code up to the catch without executing any of that source code. It doesn't have anything to do with errors, reporting or stopping bugs. I like to think of throwing an exception as a "super return" statement for a function. It returns execution of the code to somewhere much higher up than the original caller.

The important thing here is to understand that the true value of exceptions is in the try/catch pattern, and not the instantiation of the exception object. The exception object is just a state message.

In your question you seem to be confusing the usage of these two things: a jumping to a handler of the exception, and the error state the exception represents. Just because you took an error state and wrapped it in an exception does not mean you are following the try/catch pattern or its benefits.

For example

Returning exceptions instead of throwing them can make semantical sense when you have a helper-method for analyzing the situation and returning an appropriate exception which is then thrown by the caller (you could call this an "exception factory"). Throwing an exception in this error analyzer function would mean that something went wrong during the analysis itself, while returning an exception means that the kind of error was analyzed successfully.