# Troubleshooting<no value>
// <!-- Required for asciidoctor -->
:toc:
// Set toclevels to be at least your hugo [markup.tableOfContents.endLevel] config key
:toclevels: 4

== Description

Messages are grouped by theme and quoted as Updatecli prints them, so searching this page for the
line in your log should land on the right entry.

Before anything else, two things resolve most of what follows:

`--debug`:: Raises the log level. Several decisions (which token was used, which engine was
selected, why a target was skipped) are logged at debug level only.

`updatecli pipeline diff`:: Parses and validates the whole manifest and reports what would change
without writing anything. Every validation error on this page surfaces from a `diff`, so there is no
need to risk an `apply` to find them.

NOTE: Debug mode also switches itself on when Updatecli runs inside a CI system that reports being in
debug mode. When it does, it says so: `CI pipeline detected in Debug Mode - hence enabling debug
mode`. Jenkins, GitLab CI, and GitHub Actions are detected, see
link:/docs/help/environment/#_ci_detection["Environment variables"].

== Authentication

=== `no access token found`

[source,text]
----
failed to get access token: no access token found
----

Nothing supplied a GitHub token. Updatecli looks in this order and stops at the first hit:

. `spec.token` on the resource or scm
. `UPDATECLI_GITHUB_TOKEN`, optionally with `UPDATECLI_GITHUB_USERNAME`
. the GitHub App variables (`UPDATECLI_GITHUB_APP_CLIENT_ID` and friends)
. `GITHUB_TOKEN`, the fallback that makes GitHub Actions work without extra configuration

Run with `--debug` to see which one was picked, each path logs its own line, such as `using GitHub
token from environment variable UPDATECLI_GITHUB_TOKEN`. Silence from all four means none was set.

The full list is on the link:/docs/help/environment/["Environment variables" page].

=== `you cannot use both token and app authentication methods`

A single GitHub spec carries both `token` and `app`. Pick one. A personal access token and a GitHub
App are alternatives, not layers.

=== `github parameter(s) required: [owner,repository]`

The GitHub spec is missing `owner`, `repository`, or both. The message lists exactly which.

=== `unclear configuration, better safe than sorry`

This one deserves an explanation, because the message alone does not give you the fix. It is preceded
in the log by a longer block beginning `Better safe than sorry.`

It means Updatecli was about to force-push to a branch that is *not* a generated working branch, so
`git push --force` would land directly on, say, `main`. Rather than guess, it refuses.

Either let Updatecli use a working branch (the default), or, if pushing straight to that branch is
genuinely what you want, say so explicitly:

[source,yaml]
----
scms:
  default:
    kind: github
    spec:
      force: true
----

IMPORTANT: `force: true` means `git push --force` to the branch you named. Some targets, the `shell`
plugin in particular, commit every change in the working directory, so what gets force-pushed may be
more than you expected.

== Rate limiting

=== Updatecli appears to hang

Usually it is waiting out a GitHub rate limit, on purpose. When the remaining credit reaches zero,
Updatecli sleeps until the window resets rather than failing:

[source,text]
----
GitHub API rate limit reached, on hold for 45 minute(s) until 2026-07-30 11:15:00 UTC. The process will resume automatically.
----

There is nothing to fix in the run, it resumes by itself. To avoid the wait, reduce how many API
calls the manifest makes, or authenticate with a token that has a larger allowance. Run with
`--debug` to watch the credit drain: `GitHub API credit used 1, remaining 4998 (reset at ...)`.

=== `API rate limit already exceeded`

[source,text]
----
API rate limit already exceeded
API rate limit exceeded, final attempt failed
----

The first appears when a call starts with no credit left; Updatecli retries. The second means the
retries ran out. An unauthenticated run hits this quickly, GitHub's anonymous allowance is far
smaller than an authenticated one, so setting a token is usually the whole fix.

TIP: Docker Hub has its own, unrelated limits, with their own symptoms. See the
link:/docs/help/docker_hub_rate_limit/["Docker Hub rate limit" page].

== Git push and branches

=== `force push needed, use scm parameter "force" to true`

[source,text]
----
force push needed, use scm parameter "force" to true
----

The remote branch has commits that the local one does not, so a fast-forward push is impossible. This
normally means something else moved the branch (a previous Updatecli run, or a human).

Setting `force: true` on the scm lets Updatecli overwrite it. That is safe on a generated working
branch and destructive anywhere else, so check which branch is being pushed before reaching for the
flag.

=== `not pushing from a branch`

`HEAD` is detached, so there is no branch name to push. Usually a checkout by commit hash or tag
rather than by branch. Set `branch` on the scm.

=== `working directory has uncommitted changes`

Squashing refuses to run while the working tree is dirty, because the result would silently include
whatever was lying around. Commit or clean first.

=== Nothing to squash

[source,text]
----
feature branch updatecli_main_xxx is at same commit as base branch main, nothing to squash
feature branch updatecli_main_xxx is not ahead of base branch main
no changes found between main and updatecli_main_xxx
----

All three mean the working branch holds no new work relative to the base branch. That is the expected
outcome when a run changed nothing, not a failure to investigate.

== Commit signing

[source,text]
----
failed to load GPG key: ...
GPG key does not have a private key for signing
GPG key is still encrypted after decryption attempt
----

`failed to load GPG key`:: The armored key could not be parsed. Check that the whole block was
passed, including the `-----BEGIN PGP PRIVATE KEY BLOCK-----` header and footer, and that a multi-line
value survived however you injected it.

`GPG key does not have a private key for signing`:: A *public* key was supplied. Signing needs the
private half.

`GPG key is still encrypted after decryption attempt`:: The passphrase was missing or wrong.

The key and passphrase belong under the scm spec:

[source,yaml]
----
scms:
  default:
    kind: github
    spec:
      gpg:
        signingkey: |
          -----BEGIN PGP PRIVATE KEY BLOCK-----
          ...
        passphrase: '{{ requiredEnv "GPG_PASSPHRASE" }}'
----

== Manifest validation

These are reported before anything runs, so a `diff` finds all of them.

=== `the specified sourceid "..." for target "..." does not exist`

The target names a source that is not defined in the same manifest. Source and target identifiers are
the YAML keys, and they are case-sensitive.

=== `empty 'sourceid' for target "..."`

The target has no `sourceid` and the manifest defines **more than one** source, so Updatecli cannot
guess which value to use. With exactly one source it is inferred silently; the error only appears
once a second source exists.

Name it explicitly, or set `disablesourceinput: true` on targets that need no source value.

=== `target "..." has undefined conditionids`

A deprecated `conditionids` entry names a condition that does not exist. See
link:/docs/help/deprecations/#_stage_identifiers["Deprecations"], `conditionids` is superseded by
`dependson`.

=== `... key "..." contains forbidden go template instruction`

[source,text]
----
sources key "{{ .name }}" contains forbidden go template instruction
----

Templating is allowed in *values*, not in the identifiers a stage is keyed by. Updatecli needs stable
identifiers to resolve `sourceid` and `dependson` before templating runs. Rename the key to a literal.

=== `dependency loop detected`

Two or more stages depend on each other, directly or through a chain. Also possible:
`no valid depends_on value`, when a `dependson` entry names something that does not exist.

The link:/docs/core/order/["Execution order" page] explains how the graph is built.

=== `pipeline "..." requires Updatecli version greater than "..."`

The manifest sets a minimum version higher than the binary in use. The pipeline is skipped, not
failed, so a run can report success while doing nothing. Upgrade Updatecli, or lower the requirement
if it is no longer accurate.

== Version filtering

The most common source of "it found nothing", and the messages are terse enough to be misleading.

[source,text]
----
no version found
versions list empty
no version found matching pattern "..."
no valid semantic version found
no valid date found
no valid PEP 440 version found
wrong semantic versioning constraint "..."
unsupported version kind "..."
unsupported version kind "..." with pattern "..."
----

`versions list empty`:: The lookup itself returned nothing, the repository, registry, or API has no
versions at all. The filter is not the problem; the query is. Check the repository name and
credentials first.

`no version found matching pattern "..."`:: Versions were found, and none matched. Print the raw list
with `--debug` before adjusting the pattern.

`no valid semantic version found`:: The versions exist but are not semver, while the filter is
`kind: semver`. Tags like `2024-06-01` or `release-7` need `kind: regex` or `kind: time` instead.

`wrong semantic versioning constraint "..."`:: The constraint expression itself is malformed, `~>2.0`
rather than `~2.0`, for example.

`unsupported version kind "..."`:: A typo in `kind`. The accepted values are on the
link:/docs/core/versionfilter/["Version Filtering" page].

IMPORTANT: A version filter is a subset check, not an ordering. `kind: latest` returns what the
upstream considers latest, it does not sort the list and pick the highest. When the newest tag is not
the one you expect, that distinction is usually why.

== Nothing happened

The run finished, reported success, and opened nothing. In order of likelihood:

. **Nothing needed changing.** The normal outcome. Targets report as unchanged and no action is
  created.
. **A condition did not pass.** Conditions gate the targets of their pipeline; when one fails, those
  targets are skipped. The log names the condition.
. **Committing or pushing was switched off.** `--commit=false` and `--push=false` on
  `updatecli pipeline apply`, or running `pipeline diff`, which sets both.
. **The pipeline was filtered out.** `--pipeline-ids` and `--labels` narrow a run; anything not
  selected never executes.
. **The manifest requires a newer Updatecli.** Reported as a skip, as described above.

Run with `--debug` (the per-target result says which of these applied).

NOTE: An action whose targets all reported unchanged is not simply skipped. Updatecli still looks for
a pull request opened by an earlier run, so an update that has become obsolete is reported rather than
left dangling. See the link:/docs/core/action/["Action" page].

== Still stuck?

* Confirm the behaviour is not a documented deprecation - link:/docs/help/deprecations/[Deprecations].
* Check whether the feature needs `--experimental` - link:/docs/help/experimental/[Experimental features].
* Ask on one of the channels listed on the link:/support/[support page], including the manifest and the
  `--debug` output.
