paritytech / paritytech/contract-dependency-manager
cdm reports "Contract not found in registry" when the registry contract itself does not exist
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
cdm0.13.0 (updated from 0.8.26 during debugging; both behave the same way)- chain:
paseopreset →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:
- 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>). - 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
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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