diff --git a/appserver/payara-appserver-modules/microprofile/openapi/src/main/java/fish/payara/microprofile/openapi/api/OpenAPIBuildException.java b/appserver/payara-appserver-modules/microprofile/openapi/src/main/java/fish/payara/microprofile/openapi/api/OpenAPIBuildException.java
new file mode 100644
index 00000000000..752dde69b86
--- /dev/null
+++ b/appserver/payara-appserver-modules/microprofile/openapi/src/main/java/fish/payara/microprofile/openapi/api/OpenAPIBuildException.java
@@ -0,0 +1,48 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) [2018] Payara Foundation and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://github.com/payara/Payara/blob/master/LICENSE.txt
+ * See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at glassfish/legal/LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * The Payara Foundation designates this particular file as subject to the "Classpath"
+ * exception as provided by the Payara Foundation in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+package fish.payara.microprofile.openapi.api;
+
+public class OpenAPIBuildException extends Exception {
+    private static final long serialVersionUID = 1L;
+
+	public OpenAPIBuildException(Throwable t) {
+        super(t);
+    }
+}
\ No newline at end of file
diff --git a/appserver/payara-appserver-modules/microprofile/openapi/src/main/java/fish/payara/microprofile/openapi/impl/OpenApiService.java b/appserver/payara-appserver-modules/microprofile/openapi/src/main/java/fish/payara/microprofile/openapi/impl/OpenApiService.java
index d16fb8bd951..2db36964b06 100644
--- a/appserver/payara-appserver-modules/microprofile/openapi/src/main/java/fish/payara/microprofile/openapi/impl/OpenApiService.java
+++ b/appserver/payara-appserver-modules/microprofile/openapi/src/main/java/fish/payara/microprofile/openapi/impl/OpenApiService.java
@@ -45,7 +45,6 @@
 import java.util.Collections;
 import java.util.Deque;
 import java.util.Enumeration;
-import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentLinkedDeque;
 import java.util.logging.Logger;
@@ -72,6 +71,7 @@
 import org.jvnet.hk2.config.NotProcessed;
 import org.jvnet.hk2.config.UnprocessedChangeEvents;
 
+import fish.payara.microprofile.openapi.api.OpenAPIBuildException;
 import fish.payara.microprofile.openapi.impl.admin.OpenApiServiceConfiguration;
 import fish.payara.microprofile.openapi.impl.config.OpenApiConfiguration;
 import fish.payara.microprofile.openapi.impl.model.OpenAPIImpl;
@@ -80,6 +80,7 @@
 import fish.payara.microprofile.openapi.impl.processor.FileProcessor;
 import fish.payara.microprofile.openapi.impl.processor.FilterProcessor;
 import fish.payara.microprofile.openapi.impl.processor.ModelReaderProcessor;
+import fish.payara.nucleus.executorservice.PayaraExecutorService;
 
 @Service(name = "microprofile-openapi-service")
 @RunLevel(StartupRunLevel.VAL)
@@ -87,7 +88,7 @@ public class OpenApiService implements PostConstruct, PreDestroy, EventListener,
 
     private static final Logger LOGGER = Logger.getLogger(OpenApiService.class.getName());
 
-    private Deque<Map<ApplicationInfo, OpenAPI>> models;
+    private Deque<OpenApiMapping> mappings;
 
     @Inject
     private Events events;
@@ -95,9 +96,12 @@ public class OpenApiService implements PostConstruct, PreDestroy, EventListener,
     @Inject
     private OpenApiServiceConfiguration config;
 
+    @Inject
+    private PayaraExecutorService executor;
+
     @Override
     public void postConstruct() {
-        models = new ConcurrentLinkedDeque<>();
+        mappings = new ConcurrentLinkedDeque<>();
         events.register(this);
     }
 
@@ -113,8 +117,8 @@ public boolean isEnabled() {
     /**
      * Listen for OpenAPI config changes.
      */
-	@Override
-	public UnprocessedChangeEvents changed(PropertyChangeEvent[] event) {
+    @Override
+    public UnprocessedChangeEvents changed(PropertyChangeEvent[] event) {
         return ConfigSupport.sortAndDispatch(event, new Changed() {
             @Override
             public <T extends ConfigBeanProxy> NotProcessed changed(TYPE type, Class<T> tClass, T t) {
@@ -130,7 +134,7 @@ public <T extends ConfigBeanProxy> NotProcessed changed(TYPE type, Class<T> tCla
                 return null;
             }
         }, LOGGER);
-	}
+    }
 
     /**
      * Listen for application deployment events.
@@ -142,22 +146,15 @@ public void event(Event<?> event) {
             ApplicationInfo appInfo = (ApplicationInfo) event.hook();
 
             // Create all the relevant resources
-            if (isEnabled() && isValidApp(appInfo)) {
-                // Create the OpenAPI config
-                OpenApiConfiguration appConfig = new OpenApiConfiguration(appInfo.getAppClassLoader());
-
-                // Map the application info to a new openapi document, and store it in the list
-                Map<ApplicationInfo, OpenAPI> map = Collections.singletonMap(appInfo,
-                        createOpenApiDocument(appInfo, appConfig));
-                models.add(map);
-
-                LOGGER.info("OpenAPI document created.");
+            if (isValidApp(appInfo)) {
+                // Store the application mapping in the list
+                mappings.add(new OpenApiMapping(appInfo));
             }
         } else if (event.is(Deployment.APPLICATION_UNLOADED)) {
             ApplicationInfo appInfo = (ApplicationInfo) event.hook();
-            for (Map<ApplicationInfo, OpenAPI> map : models) {
-                if (map.keySet().toArray()[0].equals(appInfo)) {
-                    models.remove(map);
+            for (OpenApiMapping mapping : mappings) {
+                if (mapping.getAppInfo().equals(appInfo)) {
+                    mappings.remove(mapping);
                     break;
                 }
             }
@@ -165,32 +162,19 @@ public void event(Event<?> event) {
     }
 
     /**
-     * Gets the document for the most recently deployed application.
+     * @return the document for the most recently deployed application. Creates one
+     *         if it hasn't already been created.
+     * @throws OpenAPIBuildException if creating the document failed.
      */
-    public OpenAPI getDocument() {
-        if (models.isEmpty()) {
+    public OpenAPI getDocument() throws OpenAPIBuildException {
+        if (mappings.isEmpty() || !isEnabled()) {
             return null;
         }
-        return (OpenAPI) models.getLast().values().toArray()[0];
-    }
-
-    private OpenAPI createOpenApiDocument(ApplicationInfo appInfo, OpenApiConfiguration config) {
-        OpenAPI document = new OpenAPIImpl();
-
-        String contextRoot = getContextRoot(appInfo);
-        ReadableArchive archive = appInfo.getSource();
-        Set<Class<?>> classes = getClassesFromArchive(archive, appInfo.getAppClassLoader());
-
-        document = new ModelReaderProcessor().process(document, config);
-        document = new FileProcessor(appInfo.getAppClassLoader()).process(document, config);
-        document = new ApplicationProcessor(classes).process(document, config);
-        document = new BaseProcessor(contextRoot).process(document, config);
-        document = new FilterProcessor().process(document, config);
-        return document;
+        return (OpenAPI) mappings.peekLast().getDocument();
     }
 
     /**
-     * Retrieves an instance of this service from HK2.
+     * @return an instance of this service from HK2.
      */
     public static OpenApiService getInstance() {
         return Globals.getStaticBaseServiceLocator().getService(OpenApiService.class);
@@ -213,7 +197,7 @@ private static String getContextRoot(ApplicationInfo appInfo) {
     }
 
     /**
-     * @param archive the archive to read from.
+     * @param archive        the archive to read from.
      * @param appClassLoader the classloader to use to load the classes.
      * @return a list of all loadable classes in the archive.
      */
@@ -227,13 +211,13 @@ private static Set<Class<?>> getClassesFromArchive(ReadableArchive archive, Clas
                 .map(x -> {
                     Class<?> loadedClass = null;
                     // Attempt to load the class, ignoring any errors
-					try {
-						loadedClass = appClassLoader.loadClass(x);
-					} catch (Throwable t) {
+                    try {
+                        loadedClass = appClassLoader.loadClass(x);
+                    } catch (Throwable t) {
                     }
-					try {
-						loadedClass = Class.forName(x);
-					} catch (Throwable t) {
+                    try {
+                        loadedClass = Class.forName(x);
+                    } catch (Throwable t) {
                     }
                     // If the class can be loaded, check that everything in the class also can
                     if (loadedClass != null) {
@@ -247,8 +231,52 @@ private static Set<Class<?>> getClassesFromArchive(ReadableArchive archive, Clas
                     return loadedClass;
                 })
                 // Don't return null classes
-                .filter(x -> x != null)
-                .collect(toSet());
+                .filter(x -> x != null).collect(toSet());
+    }
+
+    private class OpenApiMapping {
+
+        private final ApplicationInfo appInfo;
+        private final OpenApiConfiguration appConfig;
+        private volatile OpenAPI document;
+
+        private OpenApiMapping(ApplicationInfo appInfo) {
+            this.appInfo = appInfo;
+            this.appConfig = new OpenApiConfiguration(appInfo.getAppClassLoader());
+        }
+
+        private ApplicationInfo getAppInfo() {
+            return appInfo;
+        }
+
+        private synchronized OpenAPI getDocument() throws OpenAPIBuildException {
+            if (document == null) {
+                document = buildDocument();
+            }
+            return document;
+        }
+
+        private OpenAPI buildDocument() throws OpenAPIBuildException {
+            OpenAPI openapi = new OpenAPIImpl();
+
+            try {
+                String contextRoot = getContextRoot(appInfo);
+                ReadableArchive archive = appInfo.getSource();
+                Set<Class<?>> classes = getClassesFromArchive(archive, appInfo.getAppClassLoader());
+
+                openapi = new ModelReaderProcessor().process(openapi, appConfig);
+                openapi = new FileProcessor(appInfo.getAppClassLoader()).process(openapi, appConfig);
+                openapi = new ApplicationProcessor(classes).process(openapi, appConfig);
+                openapi = new BaseProcessor(contextRoot).process(openapi, appConfig);
+                openapi = new FilterProcessor().process(openapi, appConfig);
+            } catch (Throwable t) {
+                throw new OpenAPIBuildException(t);
+            }
+
+            LOGGER.info("OpenAPI document created.");
+            return openapi;
+        }
+
     }
 
 }
\ No newline at end of file
diff --git a/appserver/payara-appserver-modules/microprofile/openapi/src/main/java/fish/payara/microprofile/openapi/impl/processor/ApplicationProcessor.java b/appserver/payara-appserver-modules/microprofile/openapi/src/main/java/fish/payara/microprofile/openapi/impl/processor/ApplicationProcessor.java
index f294df625cc..594709c7497 100644
--- a/appserver/payara-appserver-modules/microprofile/openapi/src/main/java/fish/payara/microprofile/openapi/impl/processor/ApplicationProcessor.java
+++ b/appserver/payara-appserver-modules/microprofile/openapi/src/main/java/fish/payara/microprofile/openapi/impl/processor/ApplicationProcessor.java
@@ -310,7 +310,7 @@ public void visitPATCH(PATCH patch, Method element, ApiContext context) {
 
     @Override
     public void visitProduces(Produces produces, AnnotatedElement element, ApiContext context) {
-        if (element instanceof Method) {
+        if (element instanceof Method && context.getWorkingOperation() != null) {
             for (org.eclipse.microprofile.openapi.models.responses.APIResponse response : context.getWorkingOperation()
                     .getResponses().values()) {
 
diff --git a/appserver/payara-appserver-modules/microprofile/openapi/src/main/java/fish/payara/microprofile/openapi/impl/rest/app/service/OpenApiResource.java b/appserver/payara-appserver-modules/microprofile/openapi/src/main/java/fish/payara/microprofile/openapi/impl/rest/app/service/OpenApiResource.java
index b9dff295261..12273b8ef4d 100644
--- a/appserver/payara-appserver-modules/microprofile/openapi/src/main/java/fish/payara/microprofile/openapi/impl/rest/app/service/OpenApiResource.java
+++ b/appserver/payara-appserver-modules/microprofile/openapi/src/main/java/fish/payara/microprofile/openapi/impl/rest/app/service/OpenApiResource.java
@@ -40,6 +40,7 @@
 package fish.payara.microprofile.openapi.impl.rest.app.service;
 
 import static fish.payara.microprofile.openapi.impl.rest.app.OpenApiApplication.APPLICATION_YAML;
+import static java.util.logging.Level.WARNING;
 import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
 import static javax.ws.rs.core.Response.Status.FORBIDDEN;
 
@@ -56,6 +57,7 @@
 
 import org.eclipse.microprofile.openapi.models.OpenAPI;
 
+import fish.payara.microprofile.openapi.api.OpenAPIBuildException;
 import fish.payara.microprofile.openapi.impl.OpenApiService;
 import fish.payara.microprofile.openapi.impl.model.OpenAPIImpl;
 
@@ -75,11 +77,16 @@ public Response getResponse(@Context HttpServletResponse response) throws IOExce
         }
 
         // Get the OpenAPI document
-        OpenAPI document = OpenApiService.getInstance().getDocument();
+        OpenAPI document = null;
+        try {
+            document = OpenApiService.getInstance().getDocument();
+        } catch (OpenAPIBuildException ex) {
+            LOGGER.log(WARNING, "OpenAPI document creation failed.", ex);
+        }
 
         // If there are none, return an empty OpenAPI document
         if (document == null) {
-            LOGGER.info("No document found.");
+            LOGGER.info("No OpenAPI document found.");
             return Response.status(Status.NOT_FOUND).entity(new OpenAPIImpl()).build();
         }