Skip to content

Troubleshooting

Config write rejected: "unable to parse private key" / "key is not a PEM formatted RSA private key"

Cause. github/config's prv_key field must decode as a PEM block of type RSA PRIVATE KEY (PKCS#1), and that block must itself parse as a valid RSA private key. A key in PKCS#8 (BEGIN PRIVATE KEY) format, a key with stray whitespace or line-ending corruption from copy-paste, or a non-key file entirely will fail this check.

Fix. Use the private key exactly as GitHub generates it when you download it from the App's settings page. When passing it on the CLI, use prv_key=@path/to/key.pem so the file's bytes are read directly rather than retyped or re-escaped.

Config write rejected: "unable to parse base URL"

Cause. base_url is parsed with a strict absolute-URL parser at write time. A bare hostname, a relative path, or a malformed scheme is rejected before it is ever persisted.

Fix. Supply a full base URL, e.g. https://github.example.com/api/v3 for GitHub Enterprise Server, or omit the field entirely to use the public GitHub API default.

Write rejected: "unknown field" / "unknown fields"

Cause. Every write-capable path on this engine validates the request body against its schema before doing anything else. A typo'd field name, or a field valid on one path but not another (prv_key on github/token, say), is rejected outright rather than silently ignored.

Fix. The error names the offending field(s) — check the field name against Reference: API for the path you're calling.

Token request fails: "app not installed in GitHub organization"

Cause. You supplied org_name (on github/token or a permission set) and this engine's lookup against the App's installations found no case-insensitive match for that name. This means either the name is wrong, or the App genuinely isn't installed on that organization/account.

Fix. Confirm the organization name, and confirm the App is actually installed there — check GET /github/installations (see Reference: API) for the authoritative mapping of organization names this App knows about to their installation IDs. Prefer installation_id over org_name where you can, both because it's faster (no extra API round trip) and because it sidesteps name-matching entirely.

Token request fails with a GitHub API error (4xx/5xx)

Cause. The engine forwards GitHub's own response when the access-token or installations request itself fails — a revoked App installation, an App with insufficient granted permissions for what was requested, a rate limit, or a genuine GitHub outage all surface this way. The error includes GitHub's HTTP status and response body verbatim.

Fix. Read the embedded GitHub response body — it names the actual problem (e.g. "This app is not installed" vs. a permissions mismatch vs. a rate-limit message) far more specifically than this engine can. If it's a permission mismatch, check what the App is actually granted on GitHub against what was requested in permissions.

Config appears wrong after a write, but the write "succeeded"

Cause. A github/config write is a no-op if it doesn't actually change any value — nothing is re-persisted and the cached GitHub client is not invalidated. If you intended to force a client rebuild (for example, after an out-of-band change to something the client depends on) but every field you wrote matched the existing stored value, nothing happened.

Fix. Confirm the stored values with bao read github/config first, or change at least one field to something different (then set it back if needed) to force the client to rebuild.

A CI job authenticating to OpenBao fails with 400 before it ever reaches this engine

Cause. This is not a failure in openbao-plugin-secrets-github itself — it happens one step earlier, when a workflow logs into OpenBao (for example via an OIDC-based auth backend such as auth/gha or auth/jwt) before it can call github/token at all. OpenBao's JWT-based auth backends return a 400 at login when the named role does not exist — a typo in the role name, a role that was never created, or a role created under a different auth mount path than the one the workflow is targeting all produce the same generic 400.

Fix. Confirm the role exists on the exact auth mount the workflow logs into (bao read auth/<mount>/role/<name>), and confirm the workflow's login call references that same mount and role name. This engine's own paths are never reached while this failure is happening — if you're chasing a token-minting problem and the failure is actually at login, github/config, github/token, and permission sets are all irrelevant to the fix. See .github/workflows/broker-connectivity-probe.yml in the repository for a worked example of separating an auth-layer failure like this from a genuine engine or network problem.

Verifying an engine build's provenance

Cause. GET /github/info (see Reference: API) reports empty version/build fields if the running binary wasn't built with the release -ldflags injections.

Fix. This is expected for a plain go build — see Installation. Released binaries and container images carry real values; if a production deployment shows empty fields, it was likely built from source locally rather than from a tagged release.