Key Gotchas & Architectural Rules
A curated list of critical rules, boundaries, and gotchas to keep in mind when working with Caatinga.
Critical Rules
--sourcemust be a CLI identity alias: Always use an alias (e.g.alice). Never pass a public key (G...), secret key (S...), or seed phrase.- Deploy auto-generates bindings: Pass
--no-generateif you wish to skip binding generation during CI deploys. - Full graph deploy auto-runs
wire+sync-env: Pass--no-wireor--no-sync-envto disable post-deploy hooks and environment synchronization. As of 3.9.2,sync-envno longer wipes the target env file — only the keys mapped infrontend.envare rewritten; unrelated assignments, comments, and blank lines are left untouched, and new keys are appended. (Before 3.9.2 it rebuilt the whole file, silently destroying other variables like API keys.) - Browser invoke is single-invoker only until v1.0: Multi-signer transactions (
signAuthEntry) require custom application code and throwCAATINGA_MULTI_AUTH_REQUIRED. - ZK on mainnet is blocked by default: Dev ceremony artifacts require
--allow-dev-ceremonyto build, deploy or invoke on mainnet. As of 3.10.3, mainnet is detected by network name or by the public passphrase, so renaming the network (e.g.pubnet) does not bypass the block. - Fresh machine setup: Install Node 22+, Rust, and Stellar CLI manually, then verify with
npx ctg doctor. - Errors are public API: Machine-readable
CAATINGA_*error codes must be parsed by scripts instead of parsing raw stdout/stderr text messages. read()vsinvoke():read()is a read-only simulation (no key signing, no network transaction);invoke()signs and submits an on-chain transaction.- Wallet adapters must reject on dismissal: Wallet prompts should reject on user cancellation, never leaving promises pending indefinitely.
caatinga.artifacts.jsonis git-versioned: Commit your artifacts file to version control alongside your application code.- Binding freshness is tracked automatically: Managed via
.caatinga-bindings.jsonmarkers (fresh,stale,missing,unknown). ctg doctordeploy coverage is advisory: Un-deployed contracts produce warnings but do not block CI exit code even with--strict.- Stellar CLI compatibility: Hard floor is 23.0.0; last tested is 28.0.0. Newer versions output advisory warnings.
buildRoot: When specified, runs a singlestellar contract buildfrom the Cargo workspace root rather than per-contract crate builds.buildFeatures: Cargo features passed directly tostellar contract build. Combine with--no-default-featuresto override defaults.postDeploysource override: Per-hooksourceis validated viaassertSafeSourceAccount(rejectsS...,G..., seed phrases).postDeployexpect: Verified using the Expect DSL matchers (equals,contains,matches,isArray,isNull).frontend.envsuffixes: Keys support.contractId(default),.wasmHash,.deployedAt, and.wasmPathsuffixes.doctor --strict: Fails on environment drift (--strict-env) and stale bindings (--strict-bindings).ctg regression: Local execution recipe mirroring CI:test → build → deploy --if-changed → generate → smoke.- Alias resolution: Method arguments accept
${source.address}or CLI identity aliases (length ≥ 3). identity export/import: Exports your whole Stellar config directory as a base64 tarball — not encrypted. Treat the output as key material forCAATINGA_CI_STELLAR_CONFIG_B64. Prior to 3.9.2, the archive was also left behind, world-readable, inos.tmpdir(); ifidentity export/importever ran on a machine before upgrading, check for and delete/tmp/caatinga-stellar-*.tar.gzand rotate any exposed keys. See CLI Identity Reference.- Config graph validation:
${contracts.*.contractId}placeholders indeployArgsmust be declared independsOn; validated at config load time. ctg upgradevsdeploy --upgrade: In-place preservescontractIdand invokesupgrade(); redeploy (deploy --upgrade) creates a new contract instance.read --summary/--quiet: Truncates large array payloads for clean terminal inspection on shared networks.ctg generaterequiresfrontend.bindingsOutput: Every--minimalscaffold starts without it.doctor/statusonly recommendgenerateonce the field is configured; the error prints the exact snippet to paste.- Concurrent
deploy/upgradeare safe as of 3.9.2: Artifact writes tocaatinga.artifacts.jsonare serialized with a lockfile and re-read inside the lock, so two processes running at once can no longer drop each other’scontractId. parseContractIdprefers labeled output: As of 3.9.2 it favors the last explicitly labeled contract-ID line, then the last standalone ID line, then the last bare match — and only matches the base32 alphabet (A-Z2-7) real strkeys use — so a diagnostic line printed before the real result can no longer be mistaken for the deployed contract ID.deployretries un-indexed WASM: If the RPC hasn’t yet indexed a just-uploaded WASM hash,deployretries with backoff instead of failing immediately withCAATINGA_DEPLOY_FAILED.- Mainnet confirmation cannot be turned off in config: As of 3.10.1,
requireConfirmation: falseis ignored on mainnet (by network name or by the public passphrase). In CI, pass--yesor setCAATINGA_ASSUME_YES=true; the[MAINNET GUARDRAIL]audit line is still printed. sourcePathin artifacts is relative: As of 3.10.1 bothdeployandupgradestore the relative contract path. Artifacts written by an olderctg upgrademay still contain an absolute local path until the contract is upgraded or deployed again.- Rust 1.91.1+, never 1.91.0:
stellar contract buildrefuses exactly 1.91.0 (and the 1.81–1.83 lines) withuse a rust version other than 1.81, 1.82, 1.83 or 1.91.0. As of 3.10.2,ctg doctorfails the Rust check for these and for anything older than 1.91.1. Runrustup update stable. - Source identity is required on mainnet:
deploy,invokeandupgradealways require--source. As of 3.10.3,ctg readandctg smokealso refuse the built-inalicefallback on mainnet: pass--source <alias>or setCAATINGA_SOURCE, otherwise they fail withCAATINGA_SOURCE_ACCOUNT_REQUIRED. - Mainnet uses your
rpcUrl, not the Stellar CLI’smainnetentry: The Stellar CLI’s built-inmainnetnetwork has no RPC URL (“Bring Your Own”). Caatinga 3.10.3+ always passes the configuredrpcUrlandnetworkPassphraseexplicitly on mainnet. On 3.10.2 or earlier, mainnet commands fail withInvalid URL Bring Your Own: …; upgrade instead of adding a localstellar network add mainnet.