Operation
CLI & env vars
AI agents: fetch https://docs.erpc.cloud/operation/cli.llms.txt for the complete machine-readable version of this page (full configuration schema, defaults, worked examples, and source links). Append `.llms.txt` to any docs URL for the same treatment.AIFor agents: /operation/cli.llms.txt

CLI & env vars

Three commands cover the full config lifecycle: start runs the proxy, validate catches mistakes before they reach production, and dump shows the exact effective config — defaults filled, TypeScript resolved — that the engine would actually load. Point any of them at a YAML, TypeScript, or JavaScript file, or skip the file entirely and spin up a quick test node with --endpoint.

Quick taste

Illustrative, not a tuned production config — validate a config file in CI:

cli
erpc.yaml
# shellerpc validate --config ./erpc.yaml --format json | jq .errors

Agent reference

Copy one of these prompts into your AI agent session (Claude Code, Cursor, …) — each one points the agent at this page's machine-readable reference so it can do the work correctly:

Prompt Example #1: set up config with CI validation and safe env var injection
I want to validate my eRPC config in CI before every deploy, and inject secrets
like API keys and Redis passwords safely via environment variables. My config is
my eRPC config. Read the full reference first:
https://docs.erpc.cloud/operation/cli.llms.txt
Prompt Example #2: tune metrics cardinality and histogram buckets
Audit the metrics section of my eRPC config: adjust histogram
bucket boundaries to match our typical latency distribution (10ms–10s), drop the
user and composite labels to reduce cardinality, and make sure errorLabelMode is
right for Grafana. Reference:
https://docs.erpc.cloud/operation/cli.llms.txt
Prompt Example #3: debug a TypeScript config that silently drops a function
My eRPC TypeScript config's selectionPolicy evalFunc seems to be ignored at
runtime — the dump output shows a sentinel but requests aren't being filtered.
Walk me through why TS functions can be silently dropped and how to verify they
were registered correctly. Config: ./eRPC config. Reference:
https://docs.erpc.cloud/operation/cli.llms.txt
Prompt Example #4: configure graceful shutdown for Kubernetes rolling deploys
My Kubernetes deployment sees connection errors during rolling updates. Configure
the waitBeforeShutdown and waitAfterShutdown values in my eRPC config, and set up
INSTANCE_ID via the downward API so shared-state UpdatedBy does not collide
across pods. Reference:
https://docs.erpc.cloud/operation/cli.llms.txt
Prompt Example #5: explain which logLevel and LOG_LEVEL to use in each environment
I have three environments (dev, staging, prod) and I'm unsure which log level to
set in the config file vs which to override at runtime with LOG_LEVEL. Also
explain why validate and dump always suppress logs. My config lives at my eRPC config.
Reference: https://docs.erpc.cloud/operation/cli.llms.txt
CLI & env vars — full agent referenceExpand for every option, default, and edge case — or copy this entire section into your AI assistant.

How it works

Startup sequence. main() registers a signal.NotifyContext on SIGINT/SIGTERM (cmd/erpc/main.go:L72), builds a CLI app via github.com/urfave/cli/v3, and calls cmd.Run. For the start/default action, baseCliAction calls getConfig then erpc.Init. erpc.Init (erpc/init.go:L19) runs in order:

  1. Set zerolog global level from cfg.LogLevel.
  2. Log the final config as JSON at INFO (may contain redacted secrets).
  3. Install histogram buckets and label filter.
  4. Register a global network-alias resolver for metrics label consistency.
  5. Init EVM JSON-RPC cache if configured (failures are warnings, not fatal).
  6. Init shared-state registry if configured (same warn-on-fail pattern).
  7. Build ERPC core: tracing, rate limiters, proxy pool, shared-state fallback, vendors registry, projects registry.
  8. Call erpcInstance.Bootstrap(appCtx) — eager network bootstrap in background goroutines.
  9. Start HTTP server goroutine.
  10. Optionally start a standalone gRPC server if gRPC is enabled and does not share the HTTP v4 port.
  11. Start Prometheus metrics server.
  12. Block on <-appCtx.Done(), then sleep server.waitAfterShutdown before returning.

Config file search order. When --config and a positional argument are both absent and --require-config is not set, getConfig probes (cmd/erpc/main.go:L279-L293):

  1. ./erpc.yaml
  2. ./erpc.yml
  3. ./erpc.ts
  4. ./erpc.js
  5. /erpc.yaml
  6. /erpc.yml
  7. /erpc.ts
  8. /erpc.js
  9. /root/erpc.yaml
  10. /root/erpc.yml
  11. /root/erpc.ts
  12. /root/erpc.js

First path where fs.Stat succeeds wins. If none match and no --endpoint flag was supplied, eRPC starts with a synthetic main project using public RPC providers.

YAML loading. LoadConfig reads the file, runs os.ExpandEnv on raw bytes (common/config.go:L102), then decodes with gopkg.in/yaml.v3 in strict mode (KnownFields(true) — unknown keys are fatal). After decode: legacy migration hook (LegacyTranslateFn, wired to legacy.TranslateFromConfig at cmd/erpc/main.go:L36) fires first, potentially emitting zerolog Warn messages for deprecated fields, then SetDefaults, then Validate. Tests that exercise legacy YAML must set LegacyTranslateFn manually.

TypeScript/JS loading. loadConfigFromTypescript (common/config.go:L2686):

  1. esbuild compiles the file as an IIFE bundle (Bundle:true, Format:IIFE, Target:ES2020, Platform:Node, GlobalName:"exports").
  2. The tsLoaderWalker JS fragment is appended — it depth-first walks exports.default, assigns IDs (fn_0, fn_1, …) to every function-typed leaf, registers them in globalThis.__erpcFns[id], and stamps fn.__erpcFnId = id.
  3. Combined source is compiled to a sobek.Program (userScript) and run in a temporary runtime.
  4. JSON.stringify with a replacer converts functions to "__ts_fn__:fn_<n>" sentinels; functions not reached by the walker are dropped silently.
  5. The resulting JSON is decoded through yaml.Decoder with KnownFields(true).
  6. cfg.UserScript is set; the policy-engine pool re-runs this program in each acquired sobek runtime to reconstruct live __erpcFns references — no .toString() round-trip, closures preserved.

validate subcommand. Loads config, calls erpc.GenerateValidationReport which builds a resource tree and checks for orphan rate-limit budgets, public endpoints, and static-analysis issues. Output is JSON (default) or Markdown. Exits 0 when errors is empty, 1 otherwise. All zerolog output is silenced via zerolog.SetGlobalLevel(zerolog.Disabled) before getConfig — no warnings from SetDefaults or Validate appear on stderr.

dump subcommand. Loads config, calls policy.ResolveEffectiveSelectionPolicies to fill in the effective selectionPolicy per network as the engine would derive it, then marshals to YAML (default) or JSON. Useful for verifying what a TypeScript config actually produces. Log output is also suppressed.

Graceful shutdown. On SIGINT/SIGTERM: signal.NotifyContext cancels appCtx. The HTTP server's goroutine wakes, sleeps server.waitBeforeShutdown (default 10 s — gives Kubernetes time to mark the pod NotReady), then calls srv.Shutdown(30 s budget). The metrics server shuts down with a 5 s budget. The OTel tracer provider shuts down in a goroutine with a 5 s budget. erpc.Init blocks on <-appCtx.Done() then sleeps server.waitAfterShutdown (default 10 s) before returning, allowing in-flight requests to drain.

pprof. A //go:build pprof file registers standard net/http/pprof routes and starts a listener at 0.0.0.0:<port> (default 6060; override with ERPC_PPROF_PORT). Mutex and block profiling are enabled at rate 1. The standard binary does not include pprof — build with -tags pprof to activate.

Config schema

CLI subcommandscmd/erpc/main.go:L200-244

SubcommandFlagsBehavior
erpc [config] (root / no subcommand)--config, --endpoint/-e, --require-configSame as start: load config, run erpc.Init.
erpc start--endpoint/-e (repeatable), --require-config; root --config also honored via flag lookupStart the proxy service.
erpc validate--format json|md (default json)Validate config; exit 1 on any errors; logs suppressed.
erpc dump--format yaml|json (default yaml)Dump effective config with resolved selection policies; exit 1 on load/marshal error or unsupported format.

CLI flagscmd/erpc/main.go:L76-94

FlagTypeDefaultBehavior / footguns
--configstring""Path to config file. When non-empty, sets requireConfig=true; no fallback to auto-discovery. If the path does not exist, exits 1001.
--endpoint / -e[]string[]Zero or more upstream endpoint URLs. Validated with url.ParseRequestURI; invalid URLs abort with exit 1001. Injected as synthetic upstreams into the first project when no providers/upstreams exist.
--require-configboolfalseIf true and no config file found, aborts. Skips auto-discovery and --endpoint-only mode.
validate --formatstring"json"Output format: json or md.
dump --formatstring"yaml"Output format: yaml, yml, or json. Any other value triggers "unsupported format" and exits 1.

--set / -s is not available. Commented out at cmd/erpc/main.go:L86-90. Passing it produces a framework-level flag error before any application code runs.

Top-level Config fieldscommon/config.go:L38-68

YAML pathTypeDefaultBehavior / footguns
logLevelstring"INFO"Zerolog level. Invalid value defaults to debug with a warning. Overridable at runtime by LOG_LEVEL env var. Valid: trace, debug, info, warn, error, fatal, panic, disabled.
clusterKeystring"erpc-default"Logical replica group ID for shared-state scoping. Propagated to database.sharedState.clusterKey only if that field is empty. Precedence: explicit database.sharedState.clusterKey > clusterKey > hard-coded default.
server*ServerConfigempty struct then SetDefaultsHTTP/gRPC server config (bind addresses, timeouts, graceful-shutdown windows). See HTTP server.
healthCheck*HealthCheckConfigmode=networks, defaultEval=any:initializedUpstreamsHealth check endpoint behaviour.
admin*AdminConfignilAdmin JSON-RPC API; CORS defaults to * origin with no credentials when section is present.
database*DatabaseConfignilEVM JSON-RPC cache and/or shared-state connector.
projects[]*ProjectConfigsynthetic main project with public + envio providers when emptyOrdered list of project configs. When empty, SetDefaults injects a main project.
rateLimiters*RateLimiterConfignilRate limiter budgets. Budget IDs referenced by projects/upstreams/networks must exist here.
proxyPools[]*ProxyPoolConfignilHTTP proxy pool definitions.
tracing*TracingConfignilOTel tracing; defaults when set: protocol=grpc, endpoint=localhost:4317, sampleRate=1.0, serviceName=erpc.
metrics.enabled*booltrue (non-test builds)If false or nil, metrics server is not started. In test builds the default is nil.
metrics.port*int4001Prometheus scrape port.
metrics.hostV4*string"0.0.0.0"IPv4 bind address for the metrics server.
metrics.hostV6*string"[::]"IPv6 bind address.
metrics.errorLabelModeLabelMode"compact"Controls the error label on request-error counters. "compact" condenses codes; "verbose" emits full class names.
metrics.histogramBucketsstring"" (built-in defaults)Comma-separated float64 bucket boundaries. Non-float values are rejected by validation.
metrics.histogramDropLabels[]stringnilLabel names removed from every histogram to reduce cardinality.
metrics.histogramLabelOverridesmap[string][]stringnilPer-metric label keep-list; key is metric name without erpc_ prefix.
metrics.counterDropLabels[]stringnilLabel names removed from every counter carrying caller-controlled dimensions. Sums are preserved; the dimension is not.
metrics.counterLabelOverridesmap[string][]stringnilPer-metric label keep-list for counters; key is metric name without erpc_ prefix.

Environment variables

Env varWhere appliedEffect
LOG_LEVELinit() and after config decodeZerolog global level. Applied twice: first during config-loading so those logs respect it; second after decode to override cfg.LogLevel. Invalid value falls back to debug. Valid: trace, debug, info, warn, error, fatal, panic, disabled.
LOG_WRITERinit()When "console", switches from JSON to a human-readable colored writer (time format "04:05.000ms"). Must be set before process start; cannot be changed at runtime.
ERPC_NOLOGSinit() (build tag !test)When "1", silences zerolog globally and replaces the writer with io.Discard. Intended for test runs.
ERPC_NOMETRICSinit() (build tag !test)When "1", swaps the Prometheus default registry with a no-op. Irreversible within the process.
ERPC_PPROF_PORTinit() (build tag pprof)pprof listener port; default 6060. Only effective when built with -tags pprof. Binds 0.0.0.0 — all interfaces.
ERPC_IGNORE_LOCAL_ENDPOINT_VALIDATIONconfig analyzerWhen "true", skips validation of non-HTTP and local (loopback/localhost) upstream endpoints in erpc validate. [erpc/config_analyzer.go:L1024-1031]
INSTANCE_IDshared-state + consensusFirst in the instance-identity chain. Used as UpdatedBy in shared-state writes and as {instanceId} in consensus dispute-log filenames.
POD_NAMEshared-state + consensusSecond in the chain (Kubernetes pod name).
HOSTNAMEshared-state + consensusThird in the chain (OS hostname).
FORCE_TEST_LISTEN_V4common/defaults.goWhen "true" in test builds, forces server.listenV4=true.
$VAR / ${VAR} in YAMLbefore YAML parseos.ExpandEnv on raw bytes. Unset vars resolve to empty string. Footgun: if the expanded value contains : or {, quote the YAML value.
$VAR / ${VAR} in server.responseHeadersHTTP server constructionExpanded once at server startup via os.ExpandEnv. If the expanded value is empty, the header entry is silently dropped from all responses. Runs after full config decode; distinct from YAML-level expansion. [erpc/http_server.go:L135-148]
$VAR / ${VAR} in provider-generated upstream endpointsprovider resolutionExpanded when the vendor's GenerateConfigs returns each UpstreamConfig.Endpoint string. Distinct from YAML-level expansion — runs at request time, not config-load time. [thirdparty/provider.go:L67-71]
process.env.<KEY> in TSsobek runtime creationFull os.Environ() snapshot passed to TS/JS config runtime as a process.env object; also exposed as a flat env array of "KEY=VALUE" strings. A snapshot — not a live view. Because .env is loaded in init() before the TS bundle is evaluated, .env values are available here too.

Instance-identity priority chain. Two functions resolve instance ID:

  • Shared-state: INSTANCE_IDPOD_NAMEHOSTNAMEos.Hostname()"unknown". Whitespace is trimmed at each step. data/shared_state_registry.go:L82-98
  • Consensus: same env-var priority order but final fallback is SHA-256(unixNano+pid) truncated to 8 hex chars (computed once via sync.Once). Characters problematic for filenames (:, /, \, , *, ?, ") are sanitized to _ before the value is used as the {instanceId} token in dispute-log filenames. consensus/export_utils.go:L26-48

Setting INSTANCE_ID explicitly avoids both failure modes.

validate command output schema (JSON):

{
  "errors":   [],
  "warnings": [],
  "notices":  [],
  "resources": {
    "totals": { "projectsTotal": 0, "networksTotal": 0, "upstreamsTotal": 0, "rateLimitBudgetsTotal": 0 },
    "tree": {
      "projects":     [{ "id": "", "networks": [{ "id": "", "upstreams": [{ "id": "" }] }] }],
      "rateLimiters": { "budgets": [{ "id": "", "rulesCount": 0 }] }
    }
  }
}

Exit 0 if errors is empty, exit 1 otherwise.

Exit codesutil/exit.go:L7-10

  • 1001 (ExitCodeERPCStartFailed) — CLI/config load failure or erpc.Init error.
  • 1002 (ExitCodeHttpServerFailed) — HTTP or gRPC server fatal error.

Worked examples

All patterns below are distilled from real production fleets; comments explain the non-obvious choices.

1. CI validation gate before deploy. Production deployments run erpc validate in the pipeline before any image build or Helm upgrade. Exit code 0 means no errors; pipe through jq .errors for a clean failure message in CI logs without JSON noise:

# exits 0 when errors=[], exits 1 when errors is non-empty
erpc validate --config ./erpc.yaml --format json | jq '.errors'
 
# Markdown for PR comments or human-readable output in CI
erpc validate --config ./erpc.yaml --format md

2. Production log level: error in prod, info in staging, info in dev. Real fleets keep logLevel: error in production (high-QPS internal workloads) to suppress routine health-check noise, info in staging and dev where visibility matters. LOG_LEVEL=debug at runtime (without a deploy) is the escape hatch when diagnosing live issues:

logLevel
erpc.yaml
# Production — suppress routine INFO chatter; errors surfaced by structured loglogLevel: error
# Staging / dev — info gives bootstrap/network visibility without trace flood# logLevel: info

3. Tuned metrics for multi-region fleet. Production edge deployments drop the user and composite histogram labels (high-cardinality from many API keys and composite request patterns) and set explicit bucket boundaries that match real p50/p99 latencies observed in the fleet. errorLabelMode: compact is always used in production to keep Prometheus cardinality bounded:

metrics
erpc.yaml
metrics:  enabled: true  port: 4001  hostV4: "0.0.0.0"  # Bucket edges aligned to observed p50 (~100ms) and p99 (~3s) latencies.  # Coarser than the default to keep time-series count down on large fleets.  histogramBuckets: "0.020,0.100,0.300,0.500,1,3,6,10"  # compact keeps error labels bounded; verbose creates a label value per  # error class — too many on multi-upstream deployments.  errorLabelMode: compact  # Drop high-cardinality labels from histograms only; counters keep them.  histogramDropLabels:    - user    - composite

4. Graceful shutdown for Kubernetes rolling deploys. Both Kubernetes and PaaS production deployments use 30s for both shutdown windows. waitBeforeShutdown gives Kubernetes time to update endpoints before the server starts refusing connections; waitAfterShutdown lets in-flight requests drain. INSTANCE_ID via the downward API prevents UpdatedBy collisions across pods in shared-state writes:

server
erpc.yaml
server:  # Allow Kubernetes to mark the pod NotReady before traffic stops arriving.  # Without this, rolling deploys produce connection errors during the gap.  waitBeforeShutdown: 30s  # Drain in-flight requests before the process exits.  waitAfterShutdown: 30s

Kubernetes pod spec fragment for the downward API:

env:
  - name: INSTANCE_ID
    valueFrom:
      fieldRef:
        fieldPath: metadata.name   # stable pod name; avoids UpdatedBy = "unknown"

5. Per-environment clusterKey for shared-state isolation. Each deployment uses a distinct clusterKey so prod, staging, and dev never share lock state. The top-level key propagates automatically unless database.sharedState.clusterKey is set explicitly:

database.sharedState
erpc.yaml
database:  sharedState:    # Unique per deployment — prod/stage/dev must not share lock state.    # If this key collides across two fleets, they race each other's locks.    clusterKey: prod-us-east-1    connector:      driver: redis      redis:        uri: ${SHARED_STATE_REDIS_URL}

6. Quick smoke-test with a bare endpoint, no config file. Spin up eRPC against a single node to verify routing — no YAML required. Useful for local testing before writing a full config:

erpc --endpoint https://mainnet.infura.io/v3/$INFURA_KEY
# equivalent: erpc start --endpoint https://mainnet.infura.io/v3/$INFURA_KEY

7. Inspect the effective config produced by a TypeScript config. TypeScript arrow functions in selectionPolicy.evalFunc show up as __ts_fn__:fn_N sentinels; everything else renders as plain YAML. Use this to verify closures were detected by the walker:

erpc dump --config ./erpc.ts --format yaml
# or JSON for programmatic diffing:
erpc dump --config ./erpc.ts --format json | jq .

Request/response behavior

The CLI layer itself does not process JSON-RPC requests. The behaviors below govern how the bootstrap interacts with the process environment.

  • .env file in os.Getwd() is loaded in init() before main() runs; values are available for YAML $VAR substitution. Non-existence is silently ignored; other errors are logged at ERROR. [cmd/erpc/main.go:L42-46]
  • LOG_LEVEL env var overrides cfg.LogLevel after config load; a config-file logLevel: error can be trumped by LOG_LEVEL=debug without editing the file. [cmd/erpc/main.go:L354-363]
  • validate and dump suppress all log output. zerolog.SetGlobalLevel(zerolog.Disabled) is called before getConfig runs (validate: cmd/erpc/main.go:L109; dump: cmd/erpc/main.go:L156); LOG_LEVEL has no effect during these commands.
  • YAML strict-mode rejects unknown fields (KnownFields(true)); this applies to the JSON round-trip from TypeScript configs too. [common/config.go:L103]
  • Shorthand upstream URLs (alchemy://KEY, infura://KEY, etc.) are converted to ProviderConfig and removed from p.Upstreams at SetDefaults time; after load they appear in p.Providers, not p.Upstreams. [common/defaults.go:L1164-1172]
  • Key validation rules enforced by Config.Validate(): server.maxTimeout must be non-zero; each project needs at least one upstream or provider; selectionPolicy.evalTimeout must be strictly less than evalInterval; onlyNetworks and ignoreNetworks on a provider are mutually exclusive; database.sharedState.lockMaxWait and updateMaxWait must each be less than fallbackTimeout; database.sharedState.lockTtl must be at least as long as fallbackTimeout; connector-level failsafe may not use consensus or hedge.quantile. [common/validation.go:L15]

Best practices

  • Run erpc validate --config ./erpc.yaml in every CI pipeline before shipping config changes — it catches unknown field typos, missing rate-limit budget references, and selectionPolicy compile errors without starting a server.
  • Use erpc dump --config ./erpc.ts --format yaml when debugging TypeScript configs to see what the engine actually sees; TS function sentinels (__ts_fn__:fn_N) confirm functions were detected correctly.
  • Always quote YAML values that may contain env vars with special characters: password: "${REDIS_PASSWORD}" not password: ${REDIS_PASSWORD} — a : in the expanded value will break YAML parsing silently.
  • Set INSTANCE_ID (or POD_NAME via the Kubernetes downward API) explicitly in every deployment — without it, shared-state UpdatedBy falls back to "unknown" and collides across pods; consensus dispute-log filenames get unique hashes but shared-state writes do not.
  • Do not build with -tags pprof in production unless you immediately firewall-restrict ERPC_PPROF_PORT — the listener binds 0.0.0.0, not localhost.
  • Set LOG_WRITER=console only for local development; JSON output is required by every log-aggregation platform (Datadog, Grafana Loki, etc.) and the env var cannot be changed at runtime.
  • In Kubernetes, add a preStop hook or rely on server.waitBeforeShutdown (default 10 s) to let the pod reach NotReady before requests stop arriving — skip this and you will see connection errors during rolling deploys.

Edge cases & gotchas

  1. --config sets requireConfig=true implicitly. If the specified path does not exist, the process exits 1001 with no fallback to auto-discovery. [cmd/erpc/main.go:L300-302]
  2. Positional argument works in all subcommands. erpc validate ./config.yaml and erpc dump ./config.yaml both work — first positional arg is treated as a config path with requireConfig=true. [cmd/erpc/main.go:L303-305]
  3. YAML strict-mode rejects unknown fields. A typo in any YAML key is a fatal error — this also applies to the JSON round-trip from TypeScript configs.
  4. Quoted YAML values required for env vars that may contain special chars. password: "${REDIS_PASSWORD}" is safe; password: ${REDIS_PASSWORD} is not if the value contains : or {.
  5. TypeScript default-export must be the last statement. If a later expression overwrites exports.default, the earlier config object is lost. Error: "config object must be default exported from TypeScript code AND must be the last statement in the file". [common/config.go:L2715-2717]
  6. TS functions in bare arrays are not walked. The tsLoaderWalker only descends into object properties, not bare array function elements. In practice selectionPolicy functions are always object values so this rarely matters.
  7. Orphaned TS function silently dropped. A function not reached by the walker is dropped by the JSON.stringify replacer — the config field will be absent with no error. [common/config.go:L2736-2739]
  8. validate/dump suppress all log output. zerolog.SetGlobalLevel(zerolog.Disabled) is called before getConfig. Warnings from SetDefaults, legacy migration, and validation do not appear. Use jq .errors on the JSON output. LOG_LEVEL has no effect here.
  9. LOG_WRITER=console must be set before process start. Configured in init(), not hot-reloadable. In log-aggregation environments keep the default JSON writer.
  10. pprof binds 0.0.0.0. All interfaces, not localhost-only. Firewall-restrict or avoid -tags pprof in production.
  11. ERPC_NOMETRICS=1 is irreversible. Swaps the Prometheus default registry process-wide; cannot be undone within the same process.
  12. INSTANCE_ID not stable across restarts = orphaned shared-state locks. Use a deployment-stable value (pod name, container ID).
  13. dump --format csv (or any unknown format) exits 1 via a distinct code path. A marshal failure means config loaded but serialisation failed; an unsupported-format failure means serialisation was never attempted. Valid values: yaml, yml, json.
  14. Shared-state falls back to "unknown" while consensus generates a hash. In environments with no env vars and os.Hostname() failing, shared-state UpdatedBy is "unknown" (collides across pods). Consensus dispute-log filenames get a unique 8-char hash. [data/shared_state_registry.go:L82-98] [consensus/export_utils.go:L26-48]
  15. Provider endpoint env expansion runs after YAML-level expansion. Pipeline: (1) os.ExpandEnv on raw YAML bytes → YAML decode → SetDefaults (providers registered). Then at request time: (2) provider's GenerateConfigs builds endpoint strings → expandEnvVars calls os.ExpandEnv. Double-expansion is possible if the vendor builds an endpoint that itself contains $VAR literals. [thirdparty/provider.go:L67-71]
  16. --set / -s is not implemented. The flag was planned as a Helm-style dot-path override but is commented out. Passing -s or --set produces "flag provided but not defined: -s" from the CLI framework. [cmd/erpc/main.go:L86-90]
  17. Metrics server disabled in test builds. MetricsConfig.SetDefaults sets Enabled=true only when !util.IsTest(). Tests that need metrics must set metrics.enabled: true explicitly. [common/defaults.go:L750-752]
  18. gRPC shares the HTTP handler when both addresses resolve to the same port. No separate grpcServer.Start goroutine runs. [erpc/init.go:L125]
  19. Eager network bootstrap runs on appCtx; novel chains trigger the lazy path. Novel chain IDs arriving before bootstrap finishes block the request until init completes or the request context times out. [erpc/networks_registry.go:L195-212]
  20. TypeScript process.env is a snapshot, not a live view. Built once when the sobek runtime is created from os.Environ(); a restart-less env var change requires all policy engine runtimes to be recreated.

Observability

The bootstrap/CLI layer emits no Prometheus metrics of its own. Key structured log messages (zerolog JSON unless LOG_WRITER=console):

Log messageLevelWhen
"executing command" (fields: action, version, commit)INFOStart of every CLI action
"" with config fieldINFOFinal config logged before init — may contain redacted secrets
"initializing eRPC core"INFOBefore NewERPC
"initializing transports"INFOAfter core init, before server start
"shutting down gracefully..."INFOOn context cancel
"no projects found in config; will add a default 'main' project"WARNSynthetic project injected
"no providers or upstreams found in project; will use default 'public' endpoints repository"WARNPublic fallback provider injected when project has no upstreams or providers
"failed to initialize evm json rpc cache: ..."WARNCache init failure (non-fatal)
"failed to initialize shared state registry: ..."WARNShared-state init failure (non-fatal)
"invalid log level '...', defaulting to 'debug'"WARNInvalid LOG_LEVEL or logLevel value
"pprof server started at http://localhost:<port>"INFOOnly when built with -tags pprof
"networks bootstrap completed"INFOAfter all configured networks initialised

Source code entry points

Related pages

  • HTTP server — server bind addresses, timeouts, and graceful shutdown knobs.
  • Deployment — Docker and Kubernetes deployment patterns, including POD_NAME downward API setup.
  • Projects — the config structure that start and validate both load.
  • Rate limiters — budget IDs that validation checks for orphan references.
  • Observability — Prometheus metrics exposed on metrics.port.