bug: find cache: unexpected end of JSON input #920

Closed
opened 2025-08-30 17:37:03 +00:00 by earl-warren · 15 comments
Contributor

Workaround

Remove the cache and restart the runner.

Description

It started happening in the Forgejo runner, e.g. https://codeberg.org/forgejo/forgejo/actions/runs/99720#jobstep-1-3

image

Every attempt to retrieve a cache entry was met with this error.

Logs and data

debian@hetzner01:~$ ls -lh 2025-08-30-cache-corruption/ 2025-08-30-cache-corruption/cache/.cache/actcache/
2025-08-30-cache-corruption/:
total 1.6G
-rwx------ 1 root   root 1.6G Aug 30 19:16 50.log
drwxr-xr-x 3 debian root 4.0K Jan 27  2025 cache

2025-08-30-cache-corruption/cache/.cache/actcache/:
total 632K
-rw-r--r--   1 debian debian 1.0M Aug 30 19:25 bolt.db
drwxr-xr-x 258 debian debian 4.0K Jan 31  2025 cache

Extract renovate logs with some context to get all the logged lines even if not renovate specific that happened at the same time. The focus is on finding cache related log lines (they have module=artifactcache).

$ grep -C 20 '^\[renovate' 50.log > renovate-context.log

The following shows details on the problem:

[renovate/renovate]   | ::debug::zstd version: 1.5.5
[renovate/renovate] [DEBUG]   💬  ::debug::Resource Url: http://10.4.101.13:40487/26f261bd/_apis/artifactcache/cache?keys=repo-cache-1339870%252Crepo-cache-&version=1793b4a704b902d72ec688d3641f057fdd895db83a78113ff1b41e11bf435a36
[renovate/renovate]   | ::debug::Resource Url: http://10.4.101.13:40487/26f261bd/_apis/artifactcache/cache?keys=repo-cache-1339870%252Crepo-cache-&version=1793b4a704b902d72ec688d3641f057fdd895db83a78113ff1b41e11bf435a36
time="2025-08-30T16:04:04Z" level=debug msg="GET /_apis/artifactcache/cache?keys=repo-cache-1339870%2Crepo-cache-&version=1793b4a704b902d72ec688d3641f057fdd895db83a78113ff1b41e11bf435a36" func="[func2]" file="[handler.go:413]" module=artifactcache
time="2025-08-30T16:04:04Z" level=error msg="GET /_apis/artifactcache/cache?keys=repo-cache-1339870%2Crepo-cache-&version=1793b4a704b902d72ec688d3641f057fdd895db83a78113ff1b41e11bf435a36: find cache: unexpected end of JSON input" func="[responseJSON]" file="[handler.go:614]" module=artifactcache
time="2025-08-30T16:04:04Z" level=debug msg="skip gc: 2025-08-30 15:37:31.668899213 +0000 UTC m=+532010.530542208" func="[gcCache]" file="[handler.go:511]" module=artifactcache
[renovate/renovate] [DEBUG]   💬  ::debug::getCacheEntry - Attempt 1 of 2 failed with error: Cache service responded with 500
[renovate/renovate]   | ::debug::getCacheEntry - Attempt 1 of 2 failed with error: Cache service responded with 500
[renovate/renovate] [DEBUG]   💬  ::debug::getCacheEntry - Error is not retryable
[renovate/renovate]   | ::debug::getCacheEntry - Error is not retryable
[renovate/renovate]   🚧  ::warning::Failed to restore: getCacheEntry failed: Cache service responded with 500
[renovate/renovate]   | ::warning::Failed to restore: getCacheEntry failed: Cache service responded with 500
[renovate/renovate] [DEBUG]   💬  ::debug::Failed to delete archive: Error: ENOENT: no such file or directory, unlink ''
[renovate/renovate]   | ::debug::Failed to delete archive: Error: ENOENT: no such file or directory, unlink ''
[renovate/renovate]   | Cache not found for input keys: repo-cache-1339870, repo-cache-

The error (find cache: unexpected end of JSON input) happens here:

if err := db.FindOne(cache,
bolthold.Where("Repo").Eq(repo).Index("Repo").
And("Key").Eq(prefix).
And("Version").Eq(version).
And("Complete").Eq(true).
SortBy("CreatedAt").Reverse()); err == nil || !errors.Is(err, bolthold.ErrNotFound) {
if err != nil {
return nil, fmt.Errorf("find cache: %w", err)
}
return cache, nil
}

and is reported with details to the cache action but the cache action only logs Cache service responded with 500 without the details.

Verified it works by manually triggering the renovate workflow

## Workaround Remove the cache and restart the runner. ## Description It started happening in the Forgejo runner, e.g. https://codeberg.org/forgejo/forgejo/actions/runs/99720#jobstep-1-3 ![image](/attachments/961042ca-2e1d-4e62-abb1-4b8cd0247977) Every attempt to retrieve a cache entry was met with this error. ## Logs and data ```sh debian@hetzner01:~$ ls -lh 2025-08-30-cache-corruption/ 2025-08-30-cache-corruption/cache/.cache/actcache/ 2025-08-30-cache-corruption/: total 1.6G -rwx------ 1 root root 1.6G Aug 30 19:16 50.log drwxr-xr-x 3 debian root 4.0K Jan 27 2025 cache 2025-08-30-cache-corruption/cache/.cache/actcache/: total 632K -rw-r--r-- 1 debian debian 1.0M Aug 30 19:25 bolt.db drwxr-xr-x 258 debian debian 4.0K Jan 31 2025 cache ``` Extract renovate logs with some context to get all the logged lines even if not renovate specific that happened at the same time. The focus is on finding cache related log lines (they have `module=artifactcache`). ```sh $ grep -C 20 '^\[renovate' 50.log > renovate-context.log ``` The following shows details on the problem: ``` [renovate/renovate] | ::debug::zstd version: 1.5.5 [renovate/renovate] [DEBUG] 💬 ::debug::Resource Url: http://10.4.101.13:40487/26f261bd/_apis/artifactcache/cache?keys=repo-cache-1339870%252Crepo-cache-&version=1793b4a704b902d72ec688d3641f057fdd895db83a78113ff1b41e11bf435a36 [renovate/renovate] | ::debug::Resource Url: http://10.4.101.13:40487/26f261bd/_apis/artifactcache/cache?keys=repo-cache-1339870%252Crepo-cache-&version=1793b4a704b902d72ec688d3641f057fdd895db83a78113ff1b41e11bf435a36 time="2025-08-30T16:04:04Z" level=debug msg="GET /_apis/artifactcache/cache?keys=repo-cache-1339870%2Crepo-cache-&version=1793b4a704b902d72ec688d3641f057fdd895db83a78113ff1b41e11bf435a36" func="[func2]" file="[handler.go:413]" module=artifactcache time="2025-08-30T16:04:04Z" level=error msg="GET /_apis/artifactcache/cache?keys=repo-cache-1339870%2Crepo-cache-&version=1793b4a704b902d72ec688d3641f057fdd895db83a78113ff1b41e11bf435a36: find cache: unexpected end of JSON input" func="[responseJSON]" file="[handler.go:614]" module=artifactcache time="2025-08-30T16:04:04Z" level=debug msg="skip gc: 2025-08-30 15:37:31.668899213 +0000 UTC m=+532010.530542208" func="[gcCache]" file="[handler.go:511]" module=artifactcache [renovate/renovate] [DEBUG] 💬 ::debug::getCacheEntry - Attempt 1 of 2 failed with error: Cache service responded with 500 [renovate/renovate] | ::debug::getCacheEntry - Attempt 1 of 2 failed with error: Cache service responded with 500 [renovate/renovate] [DEBUG] 💬 ::debug::getCacheEntry - Error is not retryable [renovate/renovate] | ::debug::getCacheEntry - Error is not retryable [renovate/renovate] 🚧 ::warning::Failed to restore: getCacheEntry failed: Cache service responded with 500 [renovate/renovate] | ::warning::Failed to restore: getCacheEntry failed: Cache service responded with 500 [renovate/renovate] [DEBUG] 💬 ::debug::Failed to delete archive: Error: ENOENT: no such file or directory, unlink '' [renovate/renovate] | ::debug::Failed to delete archive: Error: ENOENT: no such file or directory, unlink '' [renovate/renovate] | Cache not found for input keys: repo-cache-1339870, repo-cache- ``` The error (`find cache: unexpected end of JSON input`) happens here: https://code.forgejo.org/forgejo/runner/src/commit/583adee7804faf9f38bec338299226facb72e376/act/artifactcache/handler.go#L424-L434 and is reported with details to the cache action but the cache action only logs `Cache service responded with 500` without the details. Verified it works by manually triggering the renovate workflow - Save https://codeberg.org/forgejo/forgejo/actions/runs/99811#jobstep-3-5 - Restore https://codeberg.org/forgejo/forgejo/actions/runs/99812#jobstep-1-5
Author
Contributor

The error does not show on any other runners, all of which are running v9.1.1 which rules out a v9.1.1 specific regression.

$ sudo grep -l 'getCacheEntry failed: Cache service responded with 500' /var/log/forgejo-runner/*.log
The error does not show on any other runners, all of which are running v9.1.1 which rules out a v9.1.1 specific regression. ``` $ sudo grep -l 'getCacheEntry failed: Cache service responded with 500' /var/log/forgejo-runner/*.log ```
Author
Contributor

I think it should be possible to repeat the error by spawning a new runner with the cache that was saved. I'm not able to find / separate an error other than "500" from the logs.

I think it should be possible to repeat the error by spawning a new runner with the cache that was saved. I'm not able to find / separate an error other than "500" from the logs.
Author
Contributor

For comparison, the log of a successful cache retrieval looks like:

[renovate/renovate] [DEBUG]   💬  ::debug::["repo-cache-1340584","repo-cache-"]
[renovate/renovate]   | ::debug::["repo-cache-1340584","repo-cache-"]
[renovate/renovate] [DEBUG]   💬  ::debug::Checking zstd --quiet --version
[renovate/renovate]   | ::debug::Checking zstd --quiet --version
[renovate/renovate]   | (node:31) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.
[renovate/renovate]   | (Use `node --trace-deprecation ...` to show where the warning was created)
[renovate/renovate] [DEBUG]   💬  ::debug::1.5.5
[renovate/renovate]   | ::debug::1.5.5
[renovate/renovate] [DEBUG]   💬  ::debug::zstd version: 1.5.5
[renovate/renovate]   | ::debug::zstd version: 1.5.5
[renovate/renovate] [DEBUG]   💬  ::debug::Resource Url: http://10.4.101.105:37011/42ce5bce/_apis/artifactcache/cache?keys=repo-cache-1340584%252Crepo-cache-&version=1793b4a704b902d72ec688d3641f057fdd895db83a78113ff1b41e11bf435a36
[renovate/renovate]   | ::debug::Resource Url: http://10.4.101.105:37011/42ce5bce/_apis/artifactcache/cache?keys=repo-cache-1340584%252Crepo-cache-&version=1793b4a704b902d72ec688d3641f057fdd895db83a78113ff1b41e11bf435a36
[renovate/renovate]   ⚙  ***
[renovate/renovate]   | ::add-mask::***
[renovate/renovate] [DEBUG]   💬  ::debug::Cache Result:
[renovate/renovate]   | ::debug::Cache Result:
[renovate/renovate] [DEBUG]   💬  ::debug::{"archiveLocation":"***","cacheKey":"repo-cache-1340563","result":"hit"}
[renovate/renovate]   | ::debug::{"archiveLocation":"***","cacheKey":"repo-cache-1340563","result":"hit"}
[renovate/renovate] [DEBUG]   💬  ::debug::Archive Path: /tmp/805a0edb-0c3c-4992-ad00-cc8e8117e592/cache.tzst
[renovate/renovate]   | ::debug::Archive Path: /tmp/805a0edb-0c3c-4992-ad00-cc8e8117e592/cache.tzst
[renovate/renovate] [DEBUG]   💬  ::debug::Use Azure SDK: false
[renovate/renovate]   | ::debug::Use Azure SDK: false
[renovate/renovate] [DEBUG]   💬  ::debug::Download concurrency: 8
[renovate/renovate]   | ::debug::Download concurrency: 8
[renovate/renovate] [DEBUG]   💬  ::debug::Request timeout (ms): 30000
[renovate/renovate]   | ::debug::Request timeout (ms): 30000
[renovate/renovate] [DEBUG]   💬  ::debug::Cache segment download timeout mins env var: undefined
[renovate/renovate]   | ::debug::Cache segment download timeout mins env var: undefined
[renovate/renovate] [DEBUG]   💬  ::debug::Segment download timeout (ms): 600000
[renovate/renovate]   | ::debug::Segment download timeout (ms): 600000
[renovate/renovate] [DEBUG]   💬  ::debug::Lookup only: false
[renovate/renovate]   | ::debug::Lookup only: false
[renovate/renovate]   | Cache Size: ~0 MB (629 B)
[renovate/renovate]   | [command]/usr/bin/tar -xf /tmp/805a0edb-0c3c-4992-ad00-cc8e8117e592/cache.tzst -P -C /workspace/forgejo/forgejo --use-compress-program unzstd
[renovate/renovate]   | Cache restored successfully
[renovate/renovate]   | Cache restored from key: repo-cache-1340563
[renovate/renovate]   ✅  Success - Main Load renovate repo cache
For comparison, the log of a successful cache retrieval looks like: ``` [renovate/renovate] [DEBUG] 💬 ::debug::["repo-cache-1340584","repo-cache-"] [renovate/renovate] | ::debug::["repo-cache-1340584","repo-cache-"] [renovate/renovate] [DEBUG] 💬 ::debug::Checking zstd --quiet --version [renovate/renovate] | ::debug::Checking zstd --quiet --version [renovate/renovate] | (node:31) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead. [renovate/renovate] | (Use `node --trace-deprecation ...` to show where the warning was created) [renovate/renovate] [DEBUG] 💬 ::debug::1.5.5 [renovate/renovate] | ::debug::1.5.5 [renovate/renovate] [DEBUG] 💬 ::debug::zstd version: 1.5.5 [renovate/renovate] | ::debug::zstd version: 1.5.5 [renovate/renovate] [DEBUG] 💬 ::debug::Resource Url: http://10.4.101.105:37011/42ce5bce/_apis/artifactcache/cache?keys=repo-cache-1340584%252Crepo-cache-&version=1793b4a704b902d72ec688d3641f057fdd895db83a78113ff1b41e11bf435a36 [renovate/renovate] | ::debug::Resource Url: http://10.4.101.105:37011/42ce5bce/_apis/artifactcache/cache?keys=repo-cache-1340584%252Crepo-cache-&version=1793b4a704b902d72ec688d3641f057fdd895db83a78113ff1b41e11bf435a36 [renovate/renovate] ⚙ *** [renovate/renovate] | ::add-mask::*** [renovate/renovate] [DEBUG] 💬 ::debug::Cache Result: [renovate/renovate] | ::debug::Cache Result: [renovate/renovate] [DEBUG] 💬 ::debug::{"archiveLocation":"***","cacheKey":"repo-cache-1340563","result":"hit"} [renovate/renovate] | ::debug::{"archiveLocation":"***","cacheKey":"repo-cache-1340563","result":"hit"} [renovate/renovate] [DEBUG] 💬 ::debug::Archive Path: /tmp/805a0edb-0c3c-4992-ad00-cc8e8117e592/cache.tzst [renovate/renovate] | ::debug::Archive Path: /tmp/805a0edb-0c3c-4992-ad00-cc8e8117e592/cache.tzst [renovate/renovate] [DEBUG] 💬 ::debug::Use Azure SDK: false [renovate/renovate] | ::debug::Use Azure SDK: false [renovate/renovate] [DEBUG] 💬 ::debug::Download concurrency: 8 [renovate/renovate] | ::debug::Download concurrency: 8 [renovate/renovate] [DEBUG] 💬 ::debug::Request timeout (ms): 30000 [renovate/renovate] | ::debug::Request timeout (ms): 30000 [renovate/renovate] [DEBUG] 💬 ::debug::Cache segment download timeout mins env var: undefined [renovate/renovate] | ::debug::Cache segment download timeout mins env var: undefined [renovate/renovate] [DEBUG] 💬 ::debug::Segment download timeout (ms): 600000 [renovate/renovate] | ::debug::Segment download timeout (ms): 600000 [renovate/renovate] [DEBUG] 💬 ::debug::Lookup only: false [renovate/renovate] | ::debug::Lookup only: false [renovate/renovate] | Cache Size: ~0 MB (629 B) [renovate/renovate] | [command]/usr/bin/tar -xf /tmp/805a0edb-0c3c-4992-ad00-cc8e8117e592/cache.tzst -P -C /workspace/forgejo/forgejo --use-compress-program unzstd [renovate/renovate] | Cache restored successfully [renovate/renovate] | Cache restored from key: repo-cache-1340563 [renovate/renovate] ✅ Success - Main Load renovate repo cache ```
Author
Contributor

I thought it might be that a newer bolt version is not backward compatible but... that would impact the other runners as well so not that.

I thought it might be that a newer bolt version is not backward compatible but... that would impact the other runners as well so not that.
Author
Contributor

Updated the description with the proper way to extract the error (needs -C 20 to grep on renovate and then it is quite clear). It is definitely a bolt corruption from which it does not recover. It will keep trying to find entries and fail for the same reason, stuck.

if err := db.FindOne(cache,
bolthold.Where("Repo").Eq(repo).Index("Repo").
And("Key").Eq(prefix).
And("Version").Eq(version).
And("Complete").Eq(true).
SortBy("CreatedAt").Reverse()); err == nil || !errors.Is(err, bolthold.ErrNotFound) {
if err != nil {
return nil, fmt.Errorf("find cache: %w", err)
}
return cache, nil
}

Updated the description with the proper way to extract the error (needs `-C 20` to grep on renovate and then it is quite clear). It is definitely a bolt corruption from which it does not recover. It will keep trying to find entries and fail for the same reason, stuck. https://code.forgejo.org/forgejo/runner/src/commit/583adee7804faf9f38bec338299226facb72e376/act/artifactcache/handler.go#L424-L434
Author
Contributor

I tried to reproduce the error with a new runner set to use the cache saved after the failure (bolt.db only, not the 70GB of data as they are not involvedin the query). When it starts it shows something like:

time="2025-09-01T10:43:21+02:00" level=info msg="log level changed to trace"
time="2025-09-01T10:43:21+02:00" level=info msg="Starting runner daemon"
time="2025-09-01T10:43:21+02:00" level=debug msg="gc: 2025-09-01 10:43:21.142980301 +0200 CEST m=+0.005691397" module=artifactcache
time="2025-09-01T10:43:21+02:00" level=info msg="deleted cache: &{ID:11981 Repo:forgejo/forgejo Key:setup-cache-go-deps-linux-forgejo--fdebd46c34f02da804c1a351cdf4e7f5ab15bd9350debe9b59f716c1751e5651 Version:0f2ca7c847157f38d00bd9e0f463986b953d0e64a4658656d589a9b259dcebb7 Size:2262552882 Complete:true UsedAt:1756001062 CreatedAt:1755839703}" module=artifactcache
time="2025-09-01T10:43:21+02:00" level=info msg="deleted cache: &{ID:12016 Repo:forgejo/forgejo Key:frontend-build-c9b3303067eb769832febac77de2ce3345b26ea5 Version:c91de031e296ec277aab62f10b87de9b652d7f17d837e596281a41d043101afc Size:7906203 Complete:true UsedAt:1756029897 CreatedAt:1755889084}" module=artifactcache
time="2025-09-01T10:43:21+02:00" level=info msg="deleted cache: &{ID:12017 Repo:forgejo/forgejo Key:backend-build-c9b3303067eb769832febac77de2ce3345b26ea5 Version:2fedaf4b4c10899b31370ad5ced790a1451cccdc524f6fc085886924f1201aa5 Size:35689458 Complete:true UsedAt:1756029899 CreatedAt:1755889231}" module=artifactcache
time="2025-09-01T10:43:21+02:00" level=info msg="deleted cache: &{ID:12055 Repo:forgejo/forgejo Key:frontend-build-3600fb9e3aa97b510e404587126953ec90223892 Version:c91de031e296ec277aab62f10b87de9b652d7f17d837e596281a41d043101afc Size:7907481 Complete:true UsedAt:1756021262 CreatedAt:1755960182}" module=artifactcache
time="2025-09-01T10:43:21+02:00" level=info msg="deleted cache: &{ID:12056 Repo:forgejo/forgejo Key:backend-build-3600fb9e3aa97b510e404587126953ec90223892 Version:2fedaf4b4c10899b31370ad5ced790a1451cccdc524f6fc085886924f1201aa5 Size:35691197 Complete:true UsedAt:1756021264 CreatedAt:1755960433}" module=artifactcache
time="2025-09-01T10:43:21+02:00" level=info msg="deleted cache: &{ID:12061 Repo:forgejo/forgejo Key:repo-cache-1292368 Version:1793b4a704b902d72ec688d3641f057fdd895db83a78113ff1b41e11bf435a36 Size:70460472 Complete:true UsedAt:1755972040 CreatedAt:1755965012}" module=artifactcache

which is a good indication that it is happily using it. I then proceeded to run the cache example which succeeds.

No reproducer so far.

I tried to reproduce the error with a new runner set to use the cache saved after the failure (`bolt.db` only, not the 70GB of data as they are not involvedin the query). When it starts it shows something like: ``` time="2025-09-01T10:43:21+02:00" level=info msg="log level changed to trace" time="2025-09-01T10:43:21+02:00" level=info msg="Starting runner daemon" time="2025-09-01T10:43:21+02:00" level=debug msg="gc: 2025-09-01 10:43:21.142980301 +0200 CEST m=+0.005691397" module=artifactcache time="2025-09-01T10:43:21+02:00" level=info msg="deleted cache: &{ID:11981 Repo:forgejo/forgejo Key:setup-cache-go-deps-linux-forgejo--fdebd46c34f02da804c1a351cdf4e7f5ab15bd9350debe9b59f716c1751e5651 Version:0f2ca7c847157f38d00bd9e0f463986b953d0e64a4658656d589a9b259dcebb7 Size:2262552882 Complete:true UsedAt:1756001062 CreatedAt:1755839703}" module=artifactcache time="2025-09-01T10:43:21+02:00" level=info msg="deleted cache: &{ID:12016 Repo:forgejo/forgejo Key:frontend-build-c9b3303067eb769832febac77de2ce3345b26ea5 Version:c91de031e296ec277aab62f10b87de9b652d7f17d837e596281a41d043101afc Size:7906203 Complete:true UsedAt:1756029897 CreatedAt:1755889084}" module=artifactcache time="2025-09-01T10:43:21+02:00" level=info msg="deleted cache: &{ID:12017 Repo:forgejo/forgejo Key:backend-build-c9b3303067eb769832febac77de2ce3345b26ea5 Version:2fedaf4b4c10899b31370ad5ced790a1451cccdc524f6fc085886924f1201aa5 Size:35689458 Complete:true UsedAt:1756029899 CreatedAt:1755889231}" module=artifactcache time="2025-09-01T10:43:21+02:00" level=info msg="deleted cache: &{ID:12055 Repo:forgejo/forgejo Key:frontend-build-3600fb9e3aa97b510e404587126953ec90223892 Version:c91de031e296ec277aab62f10b87de9b652d7f17d837e596281a41d043101afc Size:7907481 Complete:true UsedAt:1756021262 CreatedAt:1755960182}" module=artifactcache time="2025-09-01T10:43:21+02:00" level=info msg="deleted cache: &{ID:12056 Repo:forgejo/forgejo Key:backend-build-3600fb9e3aa97b510e404587126953ec90223892 Version:2fedaf4b4c10899b31370ad5ced790a1451cccdc524f6fc085886924f1201aa5 Size:35691197 Complete:true UsedAt:1756021264 CreatedAt:1755960433}" module=artifactcache time="2025-09-01T10:43:21+02:00" level=info msg="deleted cache: &{ID:12061 Repo:forgejo/forgejo Key:repo-cache-1292368 Version:1793b4a704b902d72ec688d3641f057fdd895db83a78113ff1b41e11bf435a36 Size:70460472 Complete:true UsedAt:1755972040 CreatedAt:1755965012}" module=artifactcache ``` which is a good indication that it is happily using it. I then proceeded to run [the cache example](https://code.forgejo.org/forgejo/end-to-end/src/branch/main/actions/example-cache/.forgejo/workflows/test.yml) which succeeds. No reproducer so far.
Author
Contributor

All entries are valid JSON.

go install go.etcd.io/bbolt/cmd/bbolt@latestst
bbolt keys /tmp/bolt.db  Cache | while read key ; do bbolt get /tmp/bolt.db  Cache $key ; done | jq .
All entries are valid JSON. ```sh go install go.etcd.io/bbolt/cmd/bbolt@latestst bbolt keys /tmp/bolt.db Cache | while read key ; do bbolt get /tmp/bolt.db Cache $key ; done | jq . ```
earl-warren changed title from bug: Failed to restore: getCacheEntry failed: Cache service responded with 500 to bug: find cache: unexpected end of JSON input 2025-09-01 10:10:31 +00:00
Author
Contributor

I extracted as much information as I could from the saved data but it does not reproduce the error.

I extracted as much information as I could from the saved data but it does not reproduce the error.
Author
Contributor

I had a thought: if finding an entry always fails in this way, then finding entries for garbage collection should also fail. But it did not. Garbage collection kept going on, happily.

debian@hetzner01:~/2025-08-30-cache-corruption$ zstdgrep 'module=artifactcache' 50.log.zst | grep 'deleted cache' | head -2
time="2025-08-24T14:00:40Z" level=info msg="deleted cache: &{ID:11698 Repo:forgejo/forgejo Key:repo-cache-1255225 Version:1793b4a704b902d72ec688d3641f057fdd895db83a78113ff1b41e11bf435a36 Size:67804412 Complete:true UsedAt:1755432105 CreatedAt:1755425031}" func="[gcCache]" file="[handler.go:554]" module=artifactcache
time="2025-08-24T14:00:40Z" level=info msg="deleted cache: &{ID:12091 Repo:forgejo/forgejo Key:backend-build-f9ecd398f9c7e48e395ea33f9a5bd6e2a57d5423 Version:2fedaf4b4c10899b31370ad5ced790a1451cccdc524f6fc085886924f1201aa5 Size:35684121 Complete:true UsedAt:1756036544 CreatedAt:1756036544}" func="[gcCache]" file="[handler.go:602]" module=artifactcache
debian@hetzner01:~/2025-08-30-cache-corruption$ zstdgrep 'module=artifactcache' 50.log.zst | grep 'deleted cache' | tail -2
time="2025-08-30T16:37:43Z" level=info msg="deleted cache: &{ID:15719 Repo:forgejo/forgejo Key:setup-cache-go-deps-linux-forgejo--f43a3aa5e8f55e29348ec6e0d6c1e94b1f04be892832f2637ba8af92edb8f975 Version:0f2ca7c847157f38d00bd9e0f463986b953d0e64a4658656d589a9b259dcebb7 Size:1095034577 Complete:true UsedAt:1756570345 CreatedAt:1756570343}" func="[gcCache]" file="[handler.go:602]" module=artifactcache
time="2025-08-30T16:37:43Z" level=info msg="deleted cache: &{ID:15722 Repo:forgejo/forgejo Key:setup-cache-go-deps-linux-forgejo--f43a3aa5e8f55e29348ec6e0d6c1e94b1f04be892832f2637ba8af92edb8f975 Version:0f2ca7c847157f38d00bd9e0f463986b953d0e64a4658656d589a9b259dcebb7 Size:1120058632 Complete:true UsedAt:1756570667 CreatedAt:1756570666}" func="[gcCache]" file="[handler.go:602]" module=artifactcache
I had a thought: if finding an entry always fails in this way, then finding entries for garbage collection should also fail. But it did not. Garbage collection kept going on, happily. ``` debian@hetzner01:~/2025-08-30-cache-corruption$ zstdgrep 'module=artifactcache' 50.log.zst | grep 'deleted cache' | head -2 time="2025-08-24T14:00:40Z" level=info msg="deleted cache: &{ID:11698 Repo:forgejo/forgejo Key:repo-cache-1255225 Version:1793b4a704b902d72ec688d3641f057fdd895db83a78113ff1b41e11bf435a36 Size:67804412 Complete:true UsedAt:1755432105 CreatedAt:1755425031}" func="[gcCache]" file="[handler.go:554]" module=artifactcache time="2025-08-24T14:00:40Z" level=info msg="deleted cache: &{ID:12091 Repo:forgejo/forgejo Key:backend-build-f9ecd398f9c7e48e395ea33f9a5bd6e2a57d5423 Version:2fedaf4b4c10899b31370ad5ced790a1451cccdc524f6fc085886924f1201aa5 Size:35684121 Complete:true UsedAt:1756036544 CreatedAt:1756036544}" func="[gcCache]" file="[handler.go:602]" module=artifactcache debian@hetzner01:~/2025-08-30-cache-corruption$ zstdgrep 'module=artifactcache' 50.log.zst | grep 'deleted cache' | tail -2 time="2025-08-30T16:37:43Z" level=info msg="deleted cache: &{ID:15719 Repo:forgejo/forgejo Key:setup-cache-go-deps-linux-forgejo--f43a3aa5e8f55e29348ec6e0d6c1e94b1f04be892832f2637ba8af92edb8f975 Version:0f2ca7c847157f38d00bd9e0f463986b953d0e64a4658656d589a9b259dcebb7 Size:1095034577 Complete:true UsedAt:1756570345 CreatedAt:1756570343}" func="[gcCache]" file="[handler.go:602]" module=artifactcache time="2025-08-30T16:37:43Z" level=info msg="deleted cache: &{ID:15722 Repo:forgejo/forgejo Key:setup-cache-go-deps-linux-forgejo--f43a3aa5e8f55e29348ec6e0d6c1e94b1f04be892832f2637ba8af92edb8f975 Version:0f2ca7c847157f38d00bd9e0f463986b953d0e64a4658656d589a9b259dcebb7 Size:1120058632 Complete:true UsedAt:1756570667 CreatedAt:1756570666}" func="[gcCache]" file="[handler.go:602]" module=artifactcache ```
Author
Contributor

Also, it cannot be because of handler that is somehow stale, the database is opened every time it is needed and closed upon completion.

Also, it cannot be because of handler that is somehow stale, the database is opened every time it is needed and closed upon completion.
Author
Contributor

One thing is wrong with that part of the code. An error in find should not be considered recoverable but fatal. It should either:

  • disable the cache
  • exit the runner
  • reset the cache completely, assuming it is corrupted beyond repair

Displaying errors in the logs is good. But continuing to run when there is no hope for recovery is bad. I favor resetting the cache because it is a safe recovery mechanism in this case. The cache action will just have to re-populate everything.

One thing is wrong with that part of the code. An error in find should not be considered recoverable but fatal. It should either: - disable the cache - exit the runner - reset the cache completely, assuming it is corrupted beyond repair Displaying errors in the logs is good. But continuing to run when there is no hope for recovery is bad. I favor resetting the cache because it is a safe recovery mechanism in this case. The cache action will just have to re-populate everything.
Owner

I favor resetting the cache because it is a safe recovery mechanism in this case. The cache action will just have to re-populate everything.

I'd make a counter-argument... I'd say that if we had a known, specific error condition, with an understandable cause, then resetting the cache could be fine. In the absence of that specific knowledge, I'd favour making error handling in the cache as disruptive as possible so that it doesn't fail with unique and interesting conditions silently.

My concern is that I don't want a situation where a cache is relatively important -- preventing a large waste of energy, ensuring developers have fast iteration cycles -- to be quietly and repeatedly failing and clearing the cache. That's a situation that could go on indefinitely without anyone realizing the impact. I think it's better to raise the profile of such an error so that it can be diagnosed, understood, and error-specific handling installed.

> I favor resetting the cache because it is a safe recovery mechanism in this case. The cache action will just have to re-populate everything. I'd make a counter-argument... I'd say that if we had a known, specific error condition, with an understandable cause, then resetting the cache could be fine. In the absence of that specific knowledge, I'd favour making error handling in the cache **as disruptive as possible** so that it doesn't fail with unique and interesting conditions silently. My concern is that I don't want a situation where a cache is relatively important -- preventing a large waste of energy, ensuring developers have fast iteration cycles -- to be quietly and repeatedly failing and clearing the cache. That's a situation that could go on indefinitely without anyone realizing the impact. I think it's better to raise the profile of such an error so that it can be diagnosed, understood, and error-specific handling installed.
Author
Contributor

You have me convinced, I'll work on a fix to exit the runner with a meaningful error message.

When that happens it will be noticed but it won't break anything: jobs will just pile up until it is restarted. Although it is disruptive, such a corruption has only occurred once in the past two years.

All past crashes were investigated and fixed, this is the first one that eludes forensic analysis (modulo a handful of crashes that were not noticed at all, it is not 100% 😁). The odds that such a hard fail creates a problem for admins are very low.

You have me convinced, I'll work on a fix to exit the runner with a meaningful error message. When that happens it will be noticed but it won't break anything: jobs will just pile up until it is restarted. Although it is disruptive, such a corruption has only occurred once in the past two years. All past crashes were investigated and fixed, this is the first one that eludes forensic analysis (modulo a handful of crashes that were not noticed at all, it is not 100% 😁). The odds that such a hard fail creates a problem for admins are very low.
Author
Contributor

Make Handler mockable #934

Make Handler mockable https://code.forgejo.org/forgejo/runner/pulls/934
Author
Contributor

#935 is in v11.0.0 released today. It does not solve that issue but it will make it more immediately visible and hopefully easier to debug.

Let's close this as there is very little chance it will happen again. And if it does, this issue does not really provide any usable insight: the data from the fail are sane and cannot be used to reproduce the problem.

https://code.forgejo.org/forgejo/runner/pulls/935 is in v11.0.0 released today. It does not solve that issue but it will make it more immediately visible and hopefully easier to debug. Let's close this as there is very little chance it will happen again. And if it does, this issue does not really provide any usable insight: the data from the fail are sane and cannot be used to reproduce the problem.
Sign in to join this conversation.
No milestone
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
forgejo/runner#920
No description provided.