public List<MODELRESULT> buildModels(ApplicationId applicationId,
                                         Optional<DockerImage> dockerImageRepository,
                                         Version wantedNodeVespaVersion,
                                         Optional<Version> versionToBuildFirst,
                                         ApplicationPackage applicationPackage,
                                         AllocatedHostsFromAllModels allocatedHosts,
                                         Instant now) {
        Instant start = Instant.now();
        log.log(Level.FINE, () -> "Will build models for " + applicationId);
        Set<Version> versions = findVersionsToBuild(applicationPackage);

        // Load models one major version at a time (in reverse order) as new major versions are allowed
        // to be non-loadable in the case where an existing application is incompatible with a new
        // major version (which is possible by the definition of major)
        List<Integer> majorVersions = majorVersionsNewestFirst(versions);

        List<MODELRESULT> builtModels = new ArrayList<>();
        // Build latest model for latest major only, if that fails build latest model for previous major
        boolean buildLatestModelForThisMajor = true;
        for (int i = 0; i < majorVersions.size(); i++) {
            int majorVersion = majorVersions.get(i);
            log.log(Level.FINE, "Building major " + majorVersion + ", versionToBuildFirst=" + versionToBuildFirst);
            try {
                builtModels.addAll(buildModelVersions(keepMajorVersion(majorVersion, versions),
                                                      applicationId, dockerImageRepository, wantedNodeVespaVersion,
                                                      applicationPackage, allocatedHosts, now,
                                                      buildLatestModelForThisMajor,
                                                      versionToBuildFirst, majorVersion));
                buildLatestModelForThisMajor = false; // We have successfully built latest model version, do it only for this major
                versionToBuildFirst = Optional.empty(); // Set to empty, cannot build this first on another major
            }
            catch (NodeAllocationException | ApplicationLockException | TransientException | QuotaExceededException e) {
                // Don't wrap this exception, and don't try to load other model versions as this is (most likely)
                // caused by the state of the system, not the model version/application combination
                throw e;
            }
            // Catch NoSuchMethodError as well, otherwise the JVM will shut down
            catch (RuntimeException | NoSuchMethodError e) {
                if (shouldSkipCreatingMajorVersionOnError(majorVersions, majorVersion, wantedNodeVespaVersion, allocatedHosts)) {
                    log.log(Level.FINE, applicationId + ": Skipping major version " + majorVersion, e);
                }
                else {
                    if (e instanceof IllegalArgumentException || e instanceof UnsupportedOperationException) {
                        var wrapped = new InvalidApplicationException("Invalid application", e);
                        deployLogger.logApplicationPackage(Level.SEVERE, Exceptions.toMessageString(wrapped));
                        throw wrapped;
                    }
                    else {
                        log.log(Level.WARNING, "Unexpected error building " + applicationId, e);
                        // Wrap it in a RuntimeException if it is an Error
                        Exception ex = (e instanceof RuntimeException re) ? re : new RuntimeException(e);
                        throw new InternalServerException("Unexpected error building " + applicationId, ex);
                    }
                }
            }
        }
        log.log(Level.FINE, () -> "Done building models for " + applicationId + ". Built models for versions " +
                                  builtModels.stream()
                                             .map(result -> result.getModel().version())
                                             .map(Version::toFullString)
                                             .collect(Collectors.toSet()) +
                                  " in " + Duration.between(start, Instant.now()));
        return builtModels;
    }
Builds all applicable model versions

@param allocatedHosts the newest version (major and minor) (which is loaded first) decides the allocated hosts
                      and assigns to this SettableOptional such that it can be used after this method returns
configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ModelsBuilder.java