Morganamilo/paru · info
package does not have an update
Error message
package does not have an update
What it means
src/devel.rs:490 (has_update) compares the locally recorded VCS commit with the latest commit resolved from the remote. If they are equal — or the caller reaches this point with no divergence — the function bails with "package does not have an update". It is a control-flow signal (bail used as a sentinel), not a malfunction: the devel package is already at the newest commit.
Solutions
- Treat this message as 'up to date' — match on the error string or refactor the API to return Ok(false)/Option instead of bailing.
- No action is needed for the package itself; it already has the latest commit.
- If you expected an update, verify the cached devel info (url.commit) is fresh — delete the stored devel info cache so it is re-fetched.
- Confirm git ls-remote returned the real remote HEAD (see error 17/18 paths) and not a stale/cached value.
Example fix
// before: treating any error as failure
match devel::has_update(&pkg).await {
Ok(_) => update(),
Err(e) => return Err(e),
}
// after: treat "no update" sentinel as up-to-date
match devel::has_update(&pkg).await {
Ok(_) => update(),
Err(e) if e.to_string().contains("package does not have an update") => { /* up to date */ }
Err(e) => return Err(e),
} Defensive patterns
Strategy: try-catch
Validate before calling
// Compare commits yourself before calling, to anticipate the no-update bail
let up_to_date = stored_devel_info
.get(&pkg.name)
.map(|info| info.commit == latest_remote_sha)
.unwrap_or(true); Try / catch
match devel::has_update(&pkg).await {
Ok(_) => update(pkg),
Err(e) if e.to_string().contains("package does not have an update") => {
// expected sentinel: package is current, not a failure
}
Err(e) => return Err(e),
} Prevention
- Treat this bail string as 'up to date' in any caller of has_update.
- Refresh the stored devel-info cache periodically so comparisons use fresh SHAs.
- When writing new callers, prefer matching on this message over blanket error propagation.
- Log it at info level, not as an error, in update sweeps.
When it happens
Trigger: Calling has_update for a VCS package whose fetched remote SHA equals the stored sha (url.commit == sha). Any caller that treats every Result from has_update as success will see this as an error even though it means 'nothing to do'.
Common situations: Running an update sweep where all -git packages are already current; re-running a devel check shortly after a previous update; a caller that forgets this specific bail is the expected no-update outcome.
Related errors
AI-assisted analysis of Morganamilo/paru@9ac3578807 (2026-09-12).
Data as JSON: /api/errors/c0fd3b8a53e558a0.
Report an issue: GitHub.
Appendix: source
Thrown at src/devel.rs:490
} else {
None
}
}
async fn has_update(style: Style, git: &str, flags: &[String], url: &RepoInfo) -> Result<()> {
let sha = ls_remote(style, git, flags, url.url.clone(), url.branch.as_deref()).await?;
debug!(
"devel check {}: '{}' == '{}' different: {}",
url.url,
url.commit,
sha,
url.commit != sha
);
if sha != *url.commit {
return Ok(());
}
bail!(tr!("package does not have an update"))
}
pub async fn fetch_devel_info(
config: &Config,
bases: &[Base],
srcinfos: &HashMap<String, Srcinfo>,
) -> Result<DevelInfo> {
let mut devel_info = DevelInfo::default();
let mut parsed = Vec::new();
let mut futures = Vec::new();
for base in bases {
let srcinfo = match base {
Base::Aur(_) => srcinfos.get(base.package_base()),
Base::Pkgbuild(c) => Some(c.srcinfo.as_ref()),
};
View on GitHub (pinned to 9ac3578807)