Skip to content

core/keystore/aptos: wrap duplicate-key Import error with ErrKeyExists sentinel - #23267

Draft
cawthorne wants to merge 1 commit into
developfrom
feature/fix-aptos-duplicate-key-startup-error
Draft

core/keystore/aptos: wrap duplicate-key Import error with ErrKeyExists sentinel#23267
cawthorne wants to merge 1 commit into
developfrom
feature/fix-aptos-duplicate-key-startup-error

Conversation

@cawthorne

@cawthorne cawthorne commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Summary

AptosKeyStore.Import returned the duplicate-key conflict as a free-standing fmt.Errorf("key with ID %s already exists", ...). The boot path in core/cmd/shell_local.go does errors.Is(err2, keystore.ErrKeyExists) to recognize and skip the dup case (so a node can re-import its already-present keys on restart), but that check returned false for the bare-string error — different pointer values, no wrap. The control flow fell through to s.errorOut(...) and os.Exit(1).

One-line fix: wrap with the existing ErrKeyExists sentinel via fmt.Errorf("%w: ...", ErrKeyExists, ...) so errors.Is correctly identifies the duplicate path, which the boot caller already handles by logging and continuing.

 return aptoskey.Key{}, fmt.Errorf("key with ID %s already exists", key.ID())
+return aptoskey.Key{}, fmt.Errorf("%w: key with ID %s already exists", ErrKeyExists, key.ID())

The user-visible error string is unchanged ("Key already exists: key with ID <id> already exists"), so existing log lines, assertion paths, and tests are unaffected.

Symptom

Production operators with hand-imported keys via in-TOML [Aptos.Keys] blocks (e.g. CRE local env, fixtures, or staging clusters that pre-seed deterministic keystores) hit Exit 1 on any node that restarts while the key is already present in the DB. The dev-build fire-drill in chainlink-data-feeds specifically demonstrates this:

chainlink env is corrupted: 0/4 feeds-zone-a-node* containers running,
feeds-zone-a-node0 (Exited (1) 41 seconds ago).

This is the textbook "CRE Aptos key-import collision" the local-cre health check warns about. Other production paths — including the typical chainlink admin keys apt create flow — do not pre-seed [Aptos.Keys] so they aren't affected; the bug is silent there.

Out of scope

The same pattern exists in cosmos, solana, stellar, p2p, etc. — those keystores' Import methods also return bare-string duplicates. They are not on the boot codepath (only EnsureKey is called, which is idempotent), so this PR is intentionally minimal. A follow-up can sweep them in a separate change if warranted.

The data-feeds apply-local-cre-settings-profile.sh regression (docker restart reuses container env, so CL_CRE_SETTINGS_DEFAULT updates don't actually apply without docker rm + docker run) is a separate issue affecting only that repo.

Tests

  • core/services/keystore/aptos_test.go line-78 existing assertions.Equal(t, ..., err2.Error()) continue to pass — the rendered string is unchanged.
  • Implicit: errors.Is(err, keystore.ErrKeyExists) now returns true for the duplicate-error path; this is the only new behavioral contract added.

@github-actions

Copy link
Copy Markdown
Contributor

✅ No conflicts with other open PRs targeting develop

@cawthorne cawthorne changed the title Fix Aptos error core/keystore/aptos: wrap duplicate-key Import error with ErrKeyExists sentinel Jul 29, 2026
@github-actions

Copy link
Copy Markdown
Contributor

I see you updated files related to core. Please run make gocs in the root directory to add a changeset as well as in the text include at least one of the following tags:

  • #added For any new functionality added.
  • #breaking_change For any functionality that requires manual action for the node to boot.
  • #bugfix For bug fixes.
  • #changed For any change to the existing functionality.
  • #db_update For any feature that introduces updates to database schema.
  • #deprecation_notice For any upcoming deprecation functionality.
  • #internal For changesets that need to be excluded from the final changelog.
  • #nops For any feature that is NOP facing and needs to be in the official Release Notes for the release.
  • #removed For any functionality/config that is removed.
  • #updated For any functionality that is updated.
  • #wip For any change that is not ready yet and external communication about it should be held off till it is feature complete.

@cl-sonarqube-production

Copy link
Copy Markdown

@trunk-io

trunk-io Bot commented Jul 29, 2026

Copy link
Copy Markdown

Static BadgeStatic BadgeStatic Badge

View Full Report ↗︎Docs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant