diff --git a/src/OpenFOAM/db/error/error.C b/src/OpenFOAM/db/error/error.C
index 5dce9fd6cdf5978e9caeb30a76fdfd1b70e34780..120ac2427a2eee52158f14bdcd40928c6367343e 100644
--- a/src/OpenFOAM/db/error/error.C
+++ b/src/OpenFOAM/db/error/error.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2014 OpenFOAM Foundation
-    Copyright (C) 2015-2021 OpenCFD Ltd.
+    Copyright (C) 2015-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -37,8 +37,24 @@ Note
 #include "StringStream.H"
 #include "foamVersion.H"
 #include "OSspecific.H"
+#include "Enum.H"
 #include "Switch.H"
 
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+const Foam::Enum
+<
+    Foam::error::handlerTypes
+>
+Foam::error::handlerNames
+({
+    { handlerTypes::DEFAULT, "default" },
+    { handlerTypes::IGNORE, "ignore" },
+    { handlerTypes::WARN, "warn" },
+    { handlerTypes::STRICT, "strict" },
+});
+
+
 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
 
 bool Foam::error::master(const label communicator)
diff --git a/src/OpenFOAM/db/error/error.H b/src/OpenFOAM/db/error/error.H
index 36b5a200bc952203ae7049fbbd63cb2487c2be62..21dfea45f1f6b5a882e28013b97d8bf75ebdde1d 100644
--- a/src/OpenFOAM/db/error/error.H
+++ b/src/OpenFOAM/db/error/error.H
@@ -53,8 +53,8 @@ SeeAlso
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef error_H
-#define error_H
+#ifndef Foam_error_H
+#define Foam_error_H
 
 #include "messageStream.H"
 #include <memory>
@@ -66,6 +66,7 @@ namespace Foam
 
 // Forward Declarations
 class OStringStream;
+template<class EnumType> class Enum;
 
 /*---------------------------------------------------------------------------*\
                             Class error Declaration
@@ -101,6 +102,21 @@ protected:
 
 public:
 
+    // Data Types
+
+        //- Handling of errors. The exact handling depends on the local context.
+        enum class handlerTypes : char
+        {
+            DEFAULT = 0,  //!< Default behaviour (local meaning)
+            IGNORE,       //!< Ignore on errors/problems
+            WARN,         //!< Warn on errors/problems
+            STRICT        //!< Fatal on errors/problems
+        };
+
+        //- Names of the error handler types
+        static const Enum<handlerTypes> handlerNames;
+
+
     // Constructors
 
         //- Construct from title string
diff --git a/src/OpenFOAM/db/functionObjects/functionObjectList/functionObjectList.C b/src/OpenFOAM/db/functionObjects/functionObjectList/functionObjectList.C
index d1e4105d0a9facbf0aa1df9b35474e3dc989aafb..3c0beb533a32a79994da1a5f60239838b56c9575 100644
--- a/src/OpenFOAM/db/functionObjects/functionObjectList/functionObjectList.C
+++ b/src/OpenFOAM/db/functionObjects/functionObjectList/functionObjectList.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2017 OpenFOAM Foundation
-    Copyright (C) 2015-2022 OpenCFD Ltd.
+    Copyright (C) 2015-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -44,7 +44,7 @@ License
 /* * * * * * * * * * * * * * * Static Member Data  * * * * * * * * * * * * * */
 
 //- Max number of warnings (per functionObject)
-static constexpr const uint32_t maxWarnings = 10u;
+static constexpr const unsigned maxWarnings = 10u;
 
 Foam::fileName Foam::functionObjectList::functionObjectDictPath
 (
@@ -52,19 +52,6 @@ Foam::fileName Foam::functionObjectList::functionObjectDictPath
 );
 
 
-const Foam::Enum
-<
-    Foam::functionObjectList::errorHandlingType
->
-Foam::functionObjectList::errorHandlingNames_
-({
-    { errorHandlingType::DEFAULT, "default" },
-    { errorHandlingType::WARN, "warn" },
-    { errorHandlingType::IGNORE, "ignore" },
-    { errorHandlingType::STRICT, "strict" },
-});
-
-
 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
 
 namespace Foam
@@ -350,12 +337,12 @@ bool Foam::functionObjectList::readFunctionObject
 }
 
 
-Foam::functionObjectList::errorHandlingType
+Foam::error::handlerTypes
 Foam::functionObjectList::getOrDefaultErrorHandling
 (
     const word& key,
     const dictionary& dict,
-    const errorHandlingType deflt
+    const error::handlerTypes deflt
 ) const
 {
     const entry* eptr = dict.findEntry(key, keyType::LITERAL);
@@ -372,16 +359,16 @@ Foam::functionObjectList::getOrDefaultErrorHandling
         {
             const word enumName(eptr->get<word>());
 
-            if (!errorHandlingNames_.found(enumName))
+            if (!error::handlerNames.found(enumName))
             {
                 // Failed the name lookup
                 FatalIOErrorInFunction(dict)
                     << enumName << " is not in enumeration: "
-                    << errorHandlingNames_ << nl
+                    << error::handlerNames << nl
                     << exit(FatalIOError);
             }
 
-            return errorHandlingNames_.get(enumName);
+            return error::handlerNames.get(enumName);
         }
     }
 
@@ -640,15 +627,15 @@ bool Foam::functionObjectList::execute()
 
         for (functionObject& funcObj : functions())
         {
-            const errorHandlingType errorHandling = *errIter;
+            const auto errorHandling = *errIter;
             ++errIter;
 
             const word& objName = funcObj.name();
 
             if
             (
-                errorHandling == errorHandlingType::WARN
-             || errorHandling == errorHandlingType::IGNORE
+                errorHandling == error::handlerTypes::WARN
+             || errorHandling == error::handlerTypes::IGNORE
             )
             {
                 // Throw FatalError, FatalIOError as exceptions
@@ -672,12 +659,12 @@ bool Foam::functionObjectList::execute()
                 catch (const Foam::error& err)
                 {
                     // Treat IOerror and error identically
-                    uint32_t nWarnings;
+                    unsigned nWarnings;
                     hadError = true;
 
                     if
                     (
-                        errorHandling != errorHandlingType::IGNORE
+                        (errorHandling != error::handlerTypes::IGNORE)
                      && (nWarnings = ++warnings_(objName)) <= maxWarnings
                     )
                     {
@@ -718,11 +705,11 @@ bool Foam::functionObjectList::execute()
                 catch (const Foam::error& err)
                 {
                     // Treat IOerror and error identically
-                    uint32_t nWarnings;
+                    unsigned nWarnings;
 
                     if
                     (
-                        errorHandling != errorHandlingType::IGNORE
+                        (errorHandling != error::handlerTypes::IGNORE)
                      && (nWarnings = ++warnings_(objName)) <= maxWarnings
                     )
                     {
@@ -851,7 +838,7 @@ bool Foam::functionObjectList::end()
 
         for (functionObject& funcObj : functions())
         {
-            const errorHandlingType errorHandling = *errIter;
+            const auto errorHandling = *errIter;
             ++errIter;
 
             const word& objName = funcObj.name();
@@ -870,11 +857,11 @@ bool Foam::functionObjectList::end()
             catch (const Foam::error& err)
             {
                 // Treat IOerror and error identically
-                uint32_t nWarnings;
+                unsigned nWarnings;
 
                 if
                 (
-                    errorHandling != errorHandlingType::IGNORE
+                    (errorHandling != error::handlerTypes::IGNORE)
                  && (nWarnings = ++warnings_(objName)) <= maxWarnings
                 )
                 {
@@ -982,7 +969,7 @@ bool Foam::functionObjectList::read()
         errorHandling_.resize
         (
             functionsDict.size(),
-            errorHandlingType::DEFAULT
+            error::handlerTypes::DEFAULT
         );
 
         HashTable<label> newIndices;
@@ -998,12 +985,12 @@ bool Foam::functionObjectList::read()
         );
 
         // Top-level "errors" specification (optional)
-        const errorHandlingType errorHandlingFallback =
+        const error::handlerTypes errorHandlingFallback =
             getOrDefaultErrorHandling
             (
                 "errors",
                 functionsDict,
-                errorHandlingType::DEFAULT
+                error::handlerTypes::DEFAULT
             );
 
         label nFunc = 0;
@@ -1045,7 +1032,7 @@ bool Foam::functionObjectList::read()
             bool enabled = dict.getOrDefault("enabled", true);
 
             // Per-function "errors" specification
-            const errorHandlingType errorHandling =
+            const error::handlerTypes errorHandling =
                 getOrDefaultErrorHandling
                 (
                     "errors",
@@ -1135,16 +1122,16 @@ bool Foam::functionObjectList::read()
 
                     switch (errorHandling)
                     {
-                        case errorHandlingType::IGNORE:
+                        case error::handlerTypes::IGNORE:
                             break;
 
-                        case errorHandlingType::STRICT:
+                        case error::handlerTypes::STRICT:
                         {
                             exitNow(err);
                             break;
                         }
 
-                        case errorHandlingType::DEFAULT:
+                        case error::handlerTypes::DEFAULT:
                         {
                             if (isA<Foam::IOerror>(err))
                             {
@@ -1157,7 +1144,7 @@ bool Foam::functionObjectList::read()
                             [[fallthrough]];
                         }
 
-                        case errorHandlingType::WARN:
+                        case error::handlerTypes::WARN:
                         {
                             // Trickery to get original message
                             err.write(Warning, false);
diff --git a/src/OpenFOAM/db/functionObjects/functionObjectList/functionObjectList.H b/src/OpenFOAM/db/functionObjects/functionObjectList/functionObjectList.H
index fa57a3c78f21272f8c3a74b7e0f637a0f0f9fc6c..da9df075273c3219f1edccccbcbc210378a473c6 100644
--- a/src/OpenFOAM/db/functionObjects/functionObjectList/functionObjectList.H
+++ b/src/OpenFOAM/db/functionObjects/functionObjectList/functionObjectList.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2015-2021 OpenCFD Ltd.
+    Copyright (C) 2015-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -78,11 +78,10 @@ SourceFiles
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef functionObjectList_H
-#define functionObjectList_H
+#ifndef Foam_functionObjectList_H
+#define Foam_functionObjectList_H
 
 #include "PtrList.H"
-#include "Enum.H"
 #include "functionObject.H"
 #include "SHA1Digest.H"
 #include "HashTable.H"
@@ -108,25 +107,10 @@ class functionObjectList
 :
     private PtrList<functionObject>
 {
-    // Data Types
-
-        //- Handling of construction or execution errors
-        enum class errorHandlingType : uint8_t
-        {
-            DEFAULT = 0,  //!< Warn on construct, Fatal on runtime
-            WARN,         //!< Warn on construct, Warn on runtime
-            IGNORE,       //!< Ignore on construct, Ignore on runtime
-            STRICT,       //!< Fatal on construct, Fatal on runtime
-        };
-
-        //- Names for error handling types
-        static const Enum<errorHandlingType> errorHandlingNames_;
-
-
     // Private Data
 
         //- A list of error/warning handling
-        List<errorHandlingType> errorHandling_;
+        List<error::handlerTypes> errorHandling_;
 
         //- A list of SHA1 digests for the function object dictionaries
         List<SHA1Digest> digests_;
@@ -137,7 +121,7 @@ class functionObjectList
         //- Track the number of warnings per function object and limit
         //  to a predefined number to avoid flooding the display.
         //  Clear on re-read of functions.
-        HashTable<uint32_t> warnings_;
+        HashTable<unsigned> warnings_;
 
         //- Reference to Time
         const Time& time_;
@@ -187,11 +171,11 @@ class functionObjectList
         //
         //  This additional treatment is to ensure that potentially existing
         //  code with an "errors" functionObject will continue to run.
-        errorHandlingType getOrDefaultErrorHandling
+        error::handlerTypes getOrDefaultErrorHandling
         (
             const word& key,
             const dictionary& dict,
-            const errorHandlingType deflt
+            const error::handlerTypes deflt
         ) const;
 
 
diff --git a/src/functionObjects/field/fieldValues/surfaceFieldValue/surfaceFieldValue.C b/src/functionObjects/field/fieldValues/surfaceFieldValue/surfaceFieldValue.C
index 0b8517c8a7e7e50afdbcc892301983445fce3953..98bf75f3ef7f914c4398bbd15c7314b3e3f79c7c 100644
--- a/src/functionObjects/field/fieldValues/surfaceFieldValue/surfaceFieldValue.C
+++ b/src/functionObjects/field/fieldValues/surfaceFieldValue/surfaceFieldValue.C
@@ -37,6 +37,9 @@ License
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
+// Max number of warnings
+static constexpr const unsigned maxWarnings = 10u;
+
 namespace Foam
 {
 namespace functionObjects
@@ -135,39 +138,13 @@ void Foam::functionObjects::fieldValues::surfaceFieldValue::setFaceZoneFaces()
         mesh_.faceZones().indices(selectionNames_)
     );
 
-    // Total number of faces selected
+    // Total number of faces that could be selected (before patch filtering)
     label numFaces = 0;
     for (const label zoneId : zoneIds)
     {
         numFaces += mesh_.faceZones()[zoneId].size();
     }
 
-    if (zoneIds.empty())
-    {
-        FatalErrorInFunction
-            << type() << ' ' << name() << ": "
-            << regionTypeNames_[regionType_] << '(' << regionName_ << "):" << nl
-            << "    No matching face zone(s): "
-            << flatOutput(selectionNames_)  << nl
-            << "    Known face zones: "
-            << flatOutput(mesh_.faceZones().names()) << nl
-            << exit(FatalError);
-    }
-
-    // Could also check this
-    #if 0
-    if (!returnReduceOr(numFaces))
-    {
-        WarningInFunction
-            << type() << ' ' << name() << ": "
-            << regionTypeNames_[regionType_] << '(' << regionName_ << "):" << nl
-            << "    The faceZone specification: "
-            << flatOutput(selectionNames_) << nl
-            << "    resulted in 0 faces" << nl
-            << exit(FatalError);
-    }
-    #endif
-
     faceId_.resize_nocopy(numFaces);
     facePatchId_.resize_nocopy(numFaces);
     faceFlip_.resize_nocopy(numFaces);
@@ -223,7 +200,75 @@ void Foam::functionObjects::fieldValues::surfaceFieldValue::setFaceZoneFaces()
     faceId_.resize(numFaces);
     facePatchId_.resize(numFaces);
     faceFlip_.resize(numFaces);
-    nFaces_ = returnReduce(faceId_.size(), sumOp<label>());
+    nFaces_ = returnReduce(numFaces, sumOp<label>());
+
+    if (!nFaces_)
+    {
+        // Raise warning or error
+        refPtr<OSstream> os;
+        bool fatal = false;
+
+        ++nWarnings_;  // Always increment (even if ignore etc)
+
+        switch (emptySurfaceError_)
+        {
+            case error::handlerTypes::IGNORE:
+            {
+                break;
+            }
+
+            case error::handlerTypes::WARN:
+            {
+                if (nWarnings_ <= maxWarnings)
+                {
+                    os.ref(WarningInFunction);
+                }
+                break;
+            }
+
+            // STRICT / DEFAULT
+            default:
+            {
+                os.ref(FatalErrorInFunction);
+                fatal = true;
+                break;
+            }
+        }
+
+        if (os)
+        {
+            os.ref()
+                << type() << ' ' << name() << ": "
+                << regionTypeNames_[regionType_]
+                << '(' << regionName_ << "):" << nl;
+
+            if (zoneIds.empty())
+            {
+                os.ref()
+                    << "    No matching face zones: "
+                    << flatOutput(selectionNames_)  << nl
+                    << "    Known face zones: "
+                    << flatOutput(mesh_.faceZones().names()) << nl;
+            }
+            else
+            {
+                os.ref()
+                    << "    The face zones: "
+                    << flatOutput(selectionNames_) << nl
+                    << "    resulted in 0 faces" << nl;
+            }
+
+            if (fatal)
+            {
+                FatalError<< exit(FatalError);
+            }
+            else if (nWarnings_ == maxWarnings)
+            {
+                os.ref()
+                    << "... suppressing further warnings." << nl;
+            }
+        }
+    }
 }
 
 
@@ -283,7 +328,7 @@ void Foam::functionObjects::fieldValues::surfaceFieldValue::setPatchFaces()
         nGood = 0;
         for (const label patchi : selected)
         {
-            if (!bad.found(patchi))
+            if (!bad.contains(patchi))
             {
                 patchIds[nGood] = patchi;
                 ++nGood;
@@ -295,36 +340,10 @@ void Foam::functionObjects::fieldValues::surfaceFieldValue::setPatchFaces()
         patchIds = std::move(selected);
     }
 
-    if (patchIds.empty())
-    {
-        FatalErrorInFunction
-            << type() << ' ' << name() << ": "
-            << regionTypeNames_[regionType_] << '(' << regionName_ << "):" << nl
-            << "    No matching patch name(s): "
-            << flatOutput(selectionNames_)  << nl
-            << "    Known patch names:" << nl
-            << mesh_.boundaryMesh().names() << nl
-            << exit(FatalError);
-    }
-
-    // Could also check this
-    #if 0
-    if (!returnReduceOr(numFaces))
-    {
-        WarningInFunction
-            << type() << ' ' << name() << ": "
-            << regionTypeNames_[regionType_] << '(' << regionName_ << "):" << nl
-            << "    The patch specification: "
-            << flatOutput(selectionNames_) << nl
-            << "    resulted in 0 faces" << nl
-            << exit(FatalError);
-    }
-    #endif
-
-    faceId_.resize(numFaces);
-    facePatchId_.resize(numFaces);
-    faceFlip_.resize(numFaces);
-    nFaces_ = returnReduce(faceId_.size(), sumOp<label>());
+    faceId_.resize_nocopy(numFaces);
+    facePatchId_.resize_nocopy(numFaces);
+    faceFlip_.resize_nocopy(numFaces);
+    nFaces_ = returnReduce(numFaces, sumOp<label>());
 
     numFaces = 0;
     for (const label patchi : patchIds)
@@ -338,6 +357,74 @@ void Foam::functionObjects::fieldValues::surfaceFieldValue::setPatchFaces()
 
         numFaces += len;
     }
+
+    if (!nFaces_)
+    {
+        // Raise warning or error
+        refPtr<OSstream> os;
+        bool fatal = false;
+
+        ++nWarnings_;  // Always increment (even if ignore etc)
+
+        switch (emptySurfaceError_)
+        {
+            case error::handlerTypes::IGNORE:
+            {
+                break;
+            }
+
+            case error::handlerTypes::WARN:
+            {
+                if (nWarnings_ <= maxWarnings)
+                {
+                    os.ref(WarningInFunction);
+                }
+                break;
+            }
+
+            // STRICT / DEFAULT
+            default:
+            {
+                os.ref(FatalErrorInFunction);
+                fatal = true;
+                break;
+            }
+        }
+
+        if (os)
+        {
+            os.ref()
+                << type() << ' ' << name() << ": "
+                << regionTypeNames_[regionType_]
+                << '(' << regionName_ << "):" << nl;
+
+            if (patchIds.empty())
+            {
+                os.ref()
+                    << "    No matching patches: "
+                    << flatOutput(selectionNames_)  << nl
+                    << "    Known patch names:" << nl
+                    << mesh_.boundaryMesh().names() << nl;
+            }
+            else
+            {
+                os.ref()
+                    << "    The patches: "
+                    << flatOutput(selectionNames_) << nl
+                    << "    resulted in 0 faces" << nl;
+            }
+
+            if (fatal)
+            {
+                FatalError<< exit(FatalError);
+            }
+            else if (nWarnings_ == maxWarnings)
+            {
+                os.ref()
+                    << "... suppressing further warnings." << nl;
+            }
+        }
+    }
 }
 
 
@@ -511,20 +598,30 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::update()
         return false;
     }
 
+    // Reset some values
+    totalArea_ = 0;
+    nFaces_ = 0;
+    bool checkEmptyFaces = true;
+
     switch (regionType_)
     {
         case stFaceZone:
         {
+            // Raises warning or error internally, don't check again
             setFaceZoneFaces();
+            checkEmptyFaces = false;
             break;
         }
         case stPatch:
         {
+            // Raises warning or error internally, don't check again
             setPatchFaces();
+            checkEmptyFaces = false;
             break;
         }
         case stObject:
         {
+            // TBD: special handling of cast errors?
             const auto& s = refCast<const polySurface>(obr());
             nFaces_ = returnReduce(s.size(), sumOp<label>());
             break;
@@ -538,23 +635,76 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::update()
         // Compiler warning if we forgot an enumeration
     }
 
-    if (nFaces_ == 0)
+    if (nFaces_)
     {
-        FatalErrorInFunction
-            << type() << ' ' << name() << ": "
-            << regionTypeNames_[regionType_] << '(' << regionName_ << "):" << nl
-            << "    Region has no faces" << exit(FatalError);
+        // Appears to be successful
+        needsUpdate_ = false;
+        totalArea_ = totalArea();   // Update the area
+        nWarnings_ = 0u;            // Reset the warnings counter
     }
+    else if (checkEmptyFaces)
+    {
+        // Raise warning or error
+        refPtr<OSstream> os;
+        bool fatal = false;
 
-    totalArea_ = totalArea();
+        ++nWarnings_;  // Always increment (even if ignore etc)
+
+        switch (emptySurfaceError_)
+        {
+            case error::handlerTypes::IGNORE:
+            {
+                break;
+            }
+
+            case error::handlerTypes::WARN:
+            {
+                if (nWarnings_ <= maxWarnings)
+                {
+                    os.ref(WarningInFunction);
+                }
+                break;
+            }
+
+            // STRICT / DEFAULT
+            default:
+            {
+                os.ref(FatalErrorInFunction);
+                fatal = true;
+                break;
+            }
+        }
+
+        if (os)
+        {
+            os.ref()
+                << type() << ' ' << name() << ": "
+                << regionTypeNames_[regionType_]
+                << '(' << regionName_ << "):" << nl
+                << "    Region has no faces" << endl;
+
+            if (fatal)
+            {
+                FatalError<< exit(FatalError);
+            }
+            else if (nWarnings_ == maxWarnings)
+            {
+                os.ref()
+                    << "... suppressing further warnings." << nl;
+            }
+        }
+    }
 
     Log << "    total faces   = " << nFaces_ << nl
         << "    total area    = " << totalArea_ << nl
         << endl;
 
-    writeFileHeader(file());
+    // Emit file header on success or change of state
+    if (nWarnings_ <= 1)
+    {
+        writeFileHeader(file());
+    }
 
-    needsUpdate_ = false;
     return true;
 }
 
@@ -931,10 +1081,12 @@ Foam::functionObjects::fieldValues::surfaceFieldValue::surfaceFieldValue
     ),
     needsUpdate_(true),
     writeArea_(false),
+    emptySurfaceError_(error::handlerTypes::DEFAULT),
     selectionNames_(),
     weightFieldNames_(),
     totalArea_(0),
     nFaces_(0),
+    nWarnings_(0),
     faceId_(),
     facePatchId_(),
     faceFlip_()
@@ -965,10 +1117,12 @@ Foam::functionObjects::fieldValues::surfaceFieldValue::surfaceFieldValue
     ),
     needsUpdate_(true),
     writeArea_(false),
+    emptySurfaceError_(error::handlerTypes::DEFAULT),
     selectionNames_(),
     weightFieldNames_(),
     totalArea_(0),
     nFaces_(0),
+    nWarnings_(0),
     faceId_(),
     facePatchId_(),
     faceFlip_()
@@ -995,12 +1149,21 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::read
 
     needsUpdate_ = true;
     writeArea_ = dict.getOrDefault("writeArea", false);
+    emptySurfaceError_ = error::handlerNames.getOrDefault
+    (
+        "empty-surface",
+        dict,
+        error::handlerTypes::DEFAULT,
+        true  // Failsafe behaviour
+    );
+
     weightFieldNames_.clear();
     // future?
     // sampleFaceScheme_ = dict.getOrDefault<word>("sampleScheme", "cell");
 
     totalArea_ = 0;
     nFaces_ = 0;
+    nWarnings_ = 0;
     faceId_.clear();
     facePatchId_.clear();
     faceFlip_.clear();
@@ -1182,12 +1345,39 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::write()
         writeCurrentTime(file());
     }
 
+    // Handle ignore/warn about empty-surface
+    if (!nFaces_)
+    {
+        totalArea_ = 0;  // Update the area (safety)
+
+        if (operation_ != opNone)
+        {
+            if (emptySurfaceError_ == error::handlerTypes::WARN)
+            {
+                if (writeArea_)
+                {
+                    Log << "    total area = " << totalArea_ << endl;
+                    file() << tab << totalArea_;
+                }
+
+                file() << tab << "NaN";
+                Log << endl;
+            }
+
+            file() << endl;
+        }
+
+        // Early exit on error
+        return true;
+    }
+
     if (writeArea_)
     {
+        // Update the area
         totalArea_ = totalArea();
         Log << "    total area = " << totalArea_ << endl;
 
-        if (operation_ != opNone && Pstream::master())
+        if (operation_ != opNone && UPstream::master())
         {
             file() << tab << totalArea_;
         }
diff --git a/src/functionObjects/field/fieldValues/surfaceFieldValue/surfaceFieldValue.H b/src/functionObjects/field/fieldValues/surfaceFieldValue/surfaceFieldValue.H
index 3782e878a7674aa947c4bf55a383a871599f1a98..efda52462a84898070619a45aa83509515b46446 100644
--- a/src/functionObjects/field/fieldValues/surfaceFieldValue/surfaceFieldValue.H
+++ b/src/functionObjects/field/fieldValues/surfaceFieldValue/surfaceFieldValue.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2017 OpenFOAM Foundation
-    Copyright (C) 2015-2020 OpenCFD Ltd.
+    Copyright (C) 2015-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -88,6 +88,7 @@ Usage
         scaleFactor     1.0;
         writeArea       false;
         surfaceFormat   none;
+        empty-surface   warn;  // default | warn | ignore | strict
 
         // Optional (inherited) entries
         ...
@@ -111,6 +112,7 @@ Usage
       writeArea    | Write the surface area             | bool |  no   | false
       surfaceFormat | Output value format               | word <!--
                 --> | conditional on writeFields  | none
+      empty-surface | Error handling for empty surfaces | enum | no | default
     \endtable
 
     The inherited entries are elaborated in:
@@ -400,6 +402,9 @@ protected:
         //- Optionally write the area of the surfaceFieldValue
         bool writeArea_;
 
+        //- Handling of empty surfaces (nFaces = 0). Default is Fatal.
+        error::handlerTypes emptySurfaceError_;
+
         //- Extended selections
         wordRes selectionNames_;
 
@@ -412,6 +417,9 @@ protected:
         //- Global number of faces
         label nFaces_;
 
+        //- Number of warnings emitted since the last valid update
+        unsigned nWarnings_;
+
 
     // If operating on mesh faces (faceZone, patch)