Skip to content

cache-memory: update_cache_memory (+ conclusion AIC cache) save fails "token has no writable scopes" — job lacks actions: write #46807

Description

@arabkin

Summary

When a workflow uses cache-memory together with threat detection, the generated update_cache_memory job (and the conclusion job's daily-AIC usage cache save) fails to write the GitHub Actions cache with:

Cache reservation failed: cache write denied: token has no writable scopes

The cache save steps are continue-on-error: true, so the run stays green — but the cache is never persisted, silently defeating cross-run cache-memory.

Root cause

pkg/workflow/cache.gobuildUpdateCacheMemoryJob assigns the job empty permissions:

permissions := NewPermissionsEmpty().RenderToYAML() // Default: no special permissions needed
if setupActionRef != "" && len(c.generateCheckoutActionsFolder(data)) > 0 {
    permissions = NewPermissionsContentsRead().RenderToYAML() // dev mode only
}

The comment "no special permissions needed" is incorrect: GitHub's cache-reservation backend requires a writable token scope. The generated job therefore gets permissions: {} (or at most contents: read), and the reservation is denied.

Key detail: the cache backend accepts only actions/contents write as a "writable scope". It does not accept issues/pull-requests write — our conclusion job carries issues: write + pull-requests: write (from safe-outputs) and its daily-AIC cache save still fails with the same "no writable scopes" error. So the fix must be actions: write specifically.

This is on main, not just a released version.

Impact

  • update_cache_memory: cross-run cache-memory never persists → the feature is effectively a no-op on affected repos.
  • conclusion: the daily-AIC usage cache save fails (artifact fallback per ADR-39266 partially mitigates, but the cache lineage never forms).
  • Repos with a read-only default GITHUB_TOKEN (Settings → Actions → Workflow permissions = read) are always affected; and because the job sets permissions: {} explicitly, even a read-write default token is overridden to zero — so it fails regardless of the org/repo default.

No configuration workaround

Per reference/permissions.md, the frontmatter permissions: block governs the agent job's read scopes (writes go through safe-outputs); it does not reach these compiler-generated infra jobs. So there is no frontmatter/recompile/upgrade way to grant the scope — the job's permissions are hardcoded in the compiler.

Proposed fix

Emit actions: write on the cache-save jobs:

  • update_cache_memory (buildUpdateCacheMemoryJob, pkg/workflow/cache.go)
  • the daily-AIC usage cache save in the conclusion job (pkg/workflow/notify_comment.go)

(actions: write is the scope GitHub documents for cache mutation; contents: write also works but is broader than needed.)

Environment

  • gh-aw: v0.81.6 (latest release at time of writing); root cause also present on main.
  • Affected regardless of actions/cache major version (reproduced on both v5.0.5 and v6.1.0).
  • Workflow config: tools.cache-memory: true, safe-outputs (threat detection enabled), permissions: read-all, repo default workflow token = read-only.

Searched existing issues/PRs for "cache", "writable scopes", "actions: write", "cache save permission" — found none tracking this.

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions