paritytech / paritytech/contract-dependency-manager

cdm reports "Contract not found in registry" when the registry contract itself does not exist

Open
#90 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
4
Forks
3
Avg merge
4d 13h
Merged PRs (30d)
3

Description

cdm reports "Contract not found in registry" when the registry contract itself doesn't exist

Summary

When the ContractRegistry is absent at the configured address, cdm reports it
as a package-level problem — "Contract not found in registry" on install,
"Failed to query registry version count" on deploy. Both messages assert the
registry answered and the package wasn't in it. In fact nothing answered.

This cost me several hours of wrong conclusions: I diagnosed a package
registration problem, then a registry migration problem, then a CLI version
problem, before checking chain storage and finding there is no registry contract
on the chain at all.

Environment

  • cdm 0.13.0 (updated from 0.8.26 during debugging; both behave the same way)
  • chain: paseo preset → wss://paseo-asset-hub-next-rpc.polkadot.io
    (src/lib/env/src/known_chains.ts:23)
  • registry addresses tried: 0xc1a73a4f93fde65b1cb1680baead248073566cb0
    (0.13 default, src/lib/env/src/registry.ts) and
    0xf62c2ece29cd8df2e10040ecfa5a894a5c5d9cb0 (our cdm.json, pre-migration)

What cdm reports

$ cdm i -n paseo @w3s/playground-registry
  Contract "@w3s/playground-registry" not found in registry

$ cdm i -n paseo @example/counter          # your own template package
  Contract "@example/counter" not found in registry

$ cdm deploy -n paseo
  Failed to query registry version count for "@w3s/playground-identity"

Both readings are wrong in the same way: they describe a registry that responded.

What is actually true

Direct storage reads against the same chain and block — not contract calls, so
there is no dry-run in the path:

address Revive.AccountInfoOf Revive.CodeInfoOf
0xc1a73a4f… (0.13 default registry) ABSENT ABSENT
0xf62c2ece… (pre-migration registry) ABSENT ABSENT
0x4a32e0FB… (our own contract, for reference) ABSENT ABSENT

The chain is alive and has contracts — Revive.AccountInfoOf enumerates 249
entries
, CodeInfoOf 102. There is simply nothing at those addresses.

I also scanned all 249 deployed contracts calling getContractCount(): none
returns a value.
That scan is meaningful because the call path demonstrably
works — of a 40-contract sample, 30 came back
success=false, ContractRevertedWithPayload, i.e. the call reached a real
contract that rejected an unknown selector.

(Caveat: a registry deployed as an EIP-1967 proxy with no implementation set
would also revert, so the scan can't exclude that specific shape.)

Chain context, in case it's the cause: block ~631,000 at 6s ⇒ genesis around
2026-08-04, and @parity/cdm-env 2.3.0 dates the registry migration to
2026-08-05. Our deploy key has nonce 0 on this chain. Consistent with the
network having been reset and the registry not (yet) redeployed.

Why the message misleads

install.ts rewrites a zero-data decode failure into the not-found message —
your own test asserts this:

// src/lib/contracts/src/install.ts (test ~:530)
test("rewrites zero-data query errors to contract-not-found with the cause attached", async () => {
    const original = new Error('Cannot decode zero data ("0x") with ABI parameters.');
    ...
    await expect(queryLatest("@example/missing", registry)).rejects.toMatchObject({
        message: 'Contract "@example/missing" not found in registry',

"Cannot decode zero data" is exactly what an absent contract produces, so
registry missing and package missing collapse into one message.

queryLatest also treats value === 0 as not-found (install.ts:176), which is
correct for a real registry — but indistinguishable here.

On the deploy side, pipeline.ts:52 throws on !success || typeof value !== "number" with the version-count wording, so the same condition surfaces under a
second, equally package-shaped message.

Suggested fix

Distinguish "no registry" from "no package" before reporting. Options:

  1. Probe the registry once per run — a no-argument call like
    getContractCount() — and if that can't be decoded, fail with something like
    No ContractRegistry at <address> on <chain> (<rpc-url>).
  2. Or check code presence at the configured address up front
    (Revive.CodeInfoOf), which needs no dry-run.

Either would have made this a thirty-second diagnosis. The address and chain in
the message matter as much as the wording — with three plausible registry
addresses in play (current, pre-migration, and whatever a stale cdm.json holds),
"not found in registry" doesn't say which registry was consulted.

The actual question I still have

Is there a ContractRegistry on paseo-asset-hub-next right now, and if not, is a
redeploy planned? Happy to --bootstrap our own if that's expected after the
reset — just want to avoid fragmenting the shared registry if one is coming
back.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with src/lib/contracts/src/install.ts, its test around line 530, and src/lib/contracts/src/pipeline.ts:52; run the existing install test and trace how zero-data query failures and failed version-count results are surfaced. Done means an absent registry and an absent package produce distinct diagnostics, with the configured address and chain context covered by tests.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
blockchain, cli
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.