apereo/cas · warning

Unable to pull changes from the remote repository. Metadata…

Error message

Unable to pull changes from the remote repository. Metadata files may be stale.

What it means

This is a WARN log, not a thrown exception, emitted by GitSamlIdPMetadataLocator.fetchInternal when gitRepository.pull() returns false during an attempt to update the local clone of the IdP metadata Git repository. The locator continues serving metadata from the last successfully pulled working copy, so the message warns that the local files may be stale relative to the remote. CAS logs it rather than failing because serving stale metadata is usually preferable to serving none.

Solutions

  1. Verify network connectivity and the remote URL configured for the Git metadata repository (git fetch manually in the configured clone directory).
  2. Check remote credentials (SSH key passphrase, deploy token) and that the CAS process user can read/write the clone directory.
  3. Inspect the clone for dirty working tree, merge conflicts, or detached HEAD; reset/clean it and retry startup.
  4. Enable DEBUG logging for the Git locator and JGit to see the underlying pull failure cause.
  5. If offline operation is intended, accept the warning or remove the git-backed locator in favor of a local filesystem locator.

Example fix

// before: relying on default remote without credentials
cas.authn.saml.idp.metadata.git.remote-url=git@internal-git:cas/metadata.git
// after: ensure reachable HTTPS remote and credentials are provisioned
cas.authn.saml.idp.metadata.git.remote-url=https://internal-git/cas/metadata.git
cas.authn.saml.idp.metadata.git.username=cas-bot
cas.authn.saml.idp.metadata.git.token=***
Defensive patterns

Strategy: validation

Validate before calling

// Before enabling the git-backed locator, probe the repo
var cmd = new ProcessBuilder("git", "-C", metadataDir, "fetch", "--dry-run");
if (cmd.start().waitFor() != 0) {
    throw new IllegalStateException("Git metadata repo unreachable or misconfigured: " + metadataDir);
}

Prevention

When it happens

Trigger: Any call to fetchInternal where the underlying Git repository pull fails: no remote configured, remote unreachable (network/DNS/proxy), authentication failure to the remote, non-git or corrupted local clone directory, merge conflicts or detached HEAD in the clone, or JGit pull returning false because the working tree is dirty.

Common situations: Deployment moved behind a firewall blocking the metadata Git remote; SSH key or token for the remote expired; the metadata repo directory was manually modified so the pull aborts; cas.authn.saml.idp.metadata.git.* remote-url misconfigured after migrating repos.

Understand the failure class

Background: "git command failed": what it means when a tool shells out to git and git exits non-zero — this error's family across 21 libraries.

Related errors


AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08). Data as JSON: /api/errors/88dd87ab73062167. Report an issue: GitHub.

Appendix: source

Thrown at support/cas-server-support-saml-idp-metadata-git/src/main/java/org/apereo/cas/support/saml/idp/metadata/GitSamlIdPMetadataLocator.java:41

 */
@Slf4j
public class GitSamlIdPMetadataLocator extends FileSystemSamlIdPMetadataLocator {
    private final GitRepository gitRepository;

    public GitSamlIdPMetadataLocator(final GitRepository gitRepository,
                                     final Cache<String, SamlIdPMetadataDocument> metadataCache,
                                     final CipherExecutor cipherExecutor,
                                     final ConfigurableApplicationContext applicationContext) {
        super(cipherExecutor, gitRepository.getRepositoryDirectory(), metadataCache, applicationContext);
        this.gitRepository = gitRepository;
    }

    @Override
    public SamlIdPMetadataDocument fetchInternal(final Optional<SamlRegisteredService> registeredService) throws Exception {
        if (gitRepository.pull()) {
            LOGGER.debug("Successfully pulled metadata changes from the remote repository");
        } else {
            LOGGER.warn("Unable to pull changes from the remote repository. Metadata files may be stale.");
        }

        val metadataFile = getMetadataArtifactFile(registeredService, "idp-metadata.xml");
        LOGGER.trace("IdP metadata file to use is [{}]", metadataFile);

        val signingKey = getMetadataArtifactFile(registeredService, "idp-signing.key");
        LOGGER.trace("IdP metadata signing key file to use is [{}]", metadataFile);

        val signingCert = getMetadataArtifactFile(registeredService, "idp-signing.crt");
        LOGGER.trace("IdP metadata signing certificate file to use is [{}]", metadataFile);

        val encryptionKey = getMetadataArtifactFile(registeredService, "idp-encryption.key");
        LOGGER.trace("IdP metadata encryption key file to use is [{}]", metadataFile);

        val encryptionCert = getMetadataArtifactFile(registeredService, "idp-encryption.crt");
        LOGGER.trace("IdP metadata encryption certificate file to use is [{}]", metadataFile);

        return SamlIdPMetadataDocument.builder()

View on GitHub (pinned to e7288fc434)