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
- Verify network connectivity and the remote URL configured for the Git metadata repository (git fetch manually in the configured clone directory).
- Check remote credentials (SSH key passphrase, deploy token) and that the CAS process user can read/write the clone directory.
- Inspect the clone for dirty working tree, merge conflicts, or detached HEAD; reset/clean it and retry startup.
- Enable DEBUG logging for the Git locator and JGit to see the underlying pull failure cause.
- 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
- Smoke-test git pull in the configured clone directory after any network or credential change
- Run the CAS process as a user with read/write access to the clone and SSH/HTTPS credentials
- Monitor logs for this WARN and alert, since stale metadata degrades silently
- Keep the clone clean: never edit files inside it manually
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
- Unable to pull changes from the remote repository. Metadata…
- not in allowed range.
- Unexpected LDAP error
- Failed to acquire access token
- Radius authentication failed
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)