Describe the bug I have 3 configurations for the vault repository and 1 for git setup under spring.cloud.config.server.composite.*. Client microservice passes multiple profiles while invoking the config server. The flow goes as below.

public class CompositeEnvironmentRepository implements EnvironmentRepository {

public Environment findOne(String application, String profile, String label, boolean includeOrigin) {
        Environment env = new Environment(application, new String[] { profile }, label, null, null);
        if (this.environmentRepositories.size() == 1) {
            Environment envRepo = this.environmentRepositories.get(0)
                .findOne(application, profile, label, includeOrigin);
            env.addAll(envRepo.getPropertySources());
            env.setVersion(envRepo.getVersion());
            env.setState(envRepo.getState());
        }
        else {
            for (EnvironmentRepository repo : environmentRepositories) {
                try {
                    env.addAll(repo.findOne(application, profile, label, includeOrigin).getPropertySources());
                }
                catch (Exception e) {.  // ****************EXCEPTION GET CAUGHT HERE****************
                    if (failOnError) {
                        throw e;
                    }
                    else {
                        log.info("Error adding environment for " + repo);
                    }
                }
            }
        }
        return env;
    }

}

public abstract class AbstractVaultEnvironmentRepository implements EnvironmentRepository, Ordered {

  @Override
 public Environment findOne(String application, String profile, String label) {
                if (ObjectUtils.isEmpty(profile)) {
                    profile = DEFAULT_PROFILE;
                }
                if (ObjectUtils.isEmpty(label)) {
                    label = defaultLabel;
                }

            var environment = new Environment(application, split(profile), label, null, getWatchState());

            var profiles = normalize(profile, DEFAULT_PROFILE);
            var applications = normalize(application, this.defaultKey);

            for (String prof : profiles) {
                for (String app : applications) {
                    var key = vaultKey(app, prof, label);
                    // read raw 'data' key from vault
                    String data = read(key); // EXCEPTION GET PROPOGATE HERE AND ENTIRE LOOP IS SKIPPED INSTEAD OF CONTINUE
                    if (data != null) {
                        // data is in json format of which, yaml is a superset, so parse
                        var yaml = new YamlPropertiesFactoryBean();
                        yaml.setResources(new ByteArrayResource(data.getBytes()));
                        var properties = yaml.getObject();

                        if (properties != null && !properties.isEmpty()) {
                            environment.add(new PropertySource("vault:" + key, properties));
                        }
                    }
                }
            }
            return environment;
    }

}

public class SpringVaultEnvironmentRepository extends AbstractVaultEnvironmentRepository {

protected String read(String key) {
        VaultResponse response = this.keyValueTemplate.get(this.path + key); // 403 EXCEPTION NOT HANDLER HERE
        if (response != null) {
            try {
                return objectMapper.writeValueAsString(response.getData());
            }
            catch (JsonProcessingException e) { // BUG HERE
                throw new RuntimeException("Error creating Vault response", e); 
            }
        }
        return null;
    }
}

}

abstract class VaultKeyValueAccessor implements VaultKeyValueOperationsSupport {

    @Nullable
        <T> T doRead(Function<RestOperations, ResponseEntity<T>> callback) {
            return (T)this.vaultOperations.doWithSession((restOperations) -> {
                try {
                    return ((ResponseEntity)callback.apply(restOperations)).getBody();
                } catch (HttpStatusCodeException e) {
                    if (HttpStatusUtil.isNotFound(e.getStatusCode())) { // RETURN NULL ONLY FOR NOT FOUND ERROR
                        return null;
                    } else {
                        throw VaultResponses.buildException(e, this.path);  // THROWS EXCEPTION FOR OTHER
                    }
            }
        });
    }

}

Sample Whenever a 403 Forriben error is sent, SpringVaultEnvironmentRepository-> read() couldn't handle it as it only handles JsonProcessException. This issue is causing a loss of the response received from the earlier executed repository. Can be reproduced on the latest version of the below jars org.springframework.cloud spring-cloud-config-server 4.2.0 org.springframework.cloud spring-cloud-starter-vault-config 4.2.0

Comment From: ryanjbaxter

See the notes on failures when using a composite environment repository here.
https://docs.spring.io/spring-cloud-config/reference/server/environment-repository/composite-repositories.html

You can set a property to allow things to continue when one environment repository has a failure.

Comment From: himnay

Yes, this flag is already set to false spring.cloud.config.server.failOnCompositeError to false. The client doesn't get an error response, but the response is partially missing.

Comment From: ryanjbaxter

Can you provide a complete, minimal, verifiable sample that reproduces the problem? It should be available as a GitHub (or similar) project or attached to this issue as a zip file.

Comment From: spring-cloud-issues

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

Comment From: spring-cloud-issues

Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.