/config/matcher.llms.txt
Matcher syntax
Write one pattern, use it everywhere. eRPC's single WildcardMatch engine handles globs (eth_*),
boolean composition (eth_* & !eth_call), and hex numeric ranges (>=0x100 & <=0x200) identically
across cache policies, failsafe rules, rate limits, method allow/ignore lists, CORS, aliasing,
upstream selectors, and routing. There is nothing new to learn when you reach a new config section.
Quick taste
Illustrative — any method, any finality; exclude debug_ from rate limits:
projects: - id: main networks: - architecture: evm evm: { chainId: 1 } failsafe: # glob + boolean: all eth_ methods except eth_call - matchMethod: "eth_* & !eth_call" retry: maxAttempts: 3Agent 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: configure failsafe rules for specific methods and finalities
I want to tune my eRPC failsafe config so different retry/hedge policies apply to different methods and finality states — e.g. aggressive retry for finalized eth_getLogs, light retry for realtime, and no hedge on tx-hash lookups. Work with my existing eRPC config. Read the matcher syntax reference first: https://docs.erpc.cloud/config/matcher.llms.txt
Prompt Example #2: build an upstream method whitelist
One of my upstreams is an archive node that should only handle eth_getLogs, eth_getBlockByNumber, eth_getBlockByHash, eth_getTransactionByHash, and eth_getTransactionReceipt — all other methods should fall to other upstreams. Configure ignoreMethods and allowMethods correctly. Work with my existing eRPC config. Reference: https://docs.erpc.cloud/config/matcher.llms.txt
Prompt Example #3: set up cache policies with hex-range and finality scoping
I want eRPC to cache eth_getLogs and block-lookup methods only for finalized and unfinalized requests, using hex block-range patterns in params so only concrete block numbers are cached (not "latest"). Work with my existing eRPC config. Reference: https://docs.erpc.cloud/config/matcher.llms.txt
Prompt Example #4: debug why my matchMethod or matchFinality rule is not matching
My eRPC failsafe rule with matchMethod "eth_get*" and matchFinality [finalized] does not seem to be picked up for some requests. Walk me through how network-scope vs upstream-scope failsafe selection works (4-tier vs config-order), and check my eRPC config for ordering mistakes or wrong finality values. Reference: https://docs.erpc.cloud/config/matcher.llms.txt
Prompt Example #5: add per-method rate-limit rules without accidentally stacking them
I want to add a rate-limit budget rule that caps debug_* and trace_* at 30 RPS and a separate rule that caps eth_getBlockReceipts at 100 RPS, but I don't want a wildcard "*" rule to stack on top and double-count. Explain how GetRulesByMethod works and write the correct rules for my eRPC config. Reference: https://docs.erpc.cloud/config/matcher.llms.txt
Matcher syntax — full agent referenceExpand for every option, default, and edge case — or copy this entire section into your AI assistant.
How it works
Core engine (WildcardMatch). Every call tokenizes the pattern string into operators (|, &,
!, (, )) and atom tokens, then builds a recursive function AST via Pratt-style
recursive-descent parsing (parseOr → parseAnd → parseUnary → parsePrimary). The resulting
func(string) bool closure is invoked immediately against the test value. There is no compiled-
pattern cache — each call re-tokenizes and re-parses. This is lightweight for short patterns but
re-tokenization cost is paid on every forwarded request for failsafe executor selection.
Glob atoms. Plain atoms (no operator prefix) are dispatched to the go-wildcard library:
* matches any number of characters, ? matches exactly one. The <empty> literal is handled
specially before the glob library — it matches only the empty string.
Boolean composition. Operator precedence, highest to lowest: NOT (!) > AND (&) > OR (|).
Parentheses override. Both & and | are left-associative. Spaces are atom separators —
"a | b" and "a|b" are identical. The characters |, &, !, (, ) cannot appear as
literals in a pattern — there is no escape mechanism.
Hex numeric comparisons. When the runtime value starts with 0x, the engine tries numeric
comparison operators (>=, <=, >, <, =) as pattern prefixes. Both sides are parsed as hex
integers. If the value does not start with 0x (e.g., a decimal block number or a named tag
like "latest"), numeric operators fall through to glob matching and will not compare as expected.
Use 0x* to match hex-format values, and combine with named tags using | for full coverage.
MatchesSelector and upstream tag awareness. The use-upstream directive and served-tip
partition grouping use MatchesSelector rather than plain WildcardMatch. The function first
tests the pattern against the upstream's id. If that matches, it returns true immediately. If
the pattern contains no ! anywhere (purely-positive), it also iterates the upstream's
tags []string and returns true on any tag match. Any ! anywhere in the pattern — even
"!other-upstream" — disables tag matching entirely. This is intentional: a tag match must never
rescue an upstream the operator meant to exclude.
matchMethodPattern helper. Inside SelectExecutor, method matching uses a helper that treats both empty string and "*" as match-anything, and tries exact equality before calling WildcardMatch to reduce overhead on common exact-match patterns. Source: common/match.go:L83-92
SelectExecutor — 4-tier priority for failsafe dispatch. Given executors with (matchMethod, matchFinality) fields and the request's (method, finality), SelectExecutor selects the first
matching executor across four tiers in priority order (single pass):
- Exact — specific method AND specific finality
- Method-only — specific method, any finality (
matchFinality: []) - Finality-only —
matchMethod: "*", specific finality - Catch-all —
matchMethod: "*",matchFinality: []
Important: upstream-level and network-level failsafe selection use different algorithms. Upstreams use the 4-tier priority algorithm above. Networks use a simpler first-match-in- config-order scan — if an any-method entry appears before a specific-method entry in config, the any-method entry wins. Place most-specific entries before catch-all entries in network-scope failsafe.
Cache policy param matching. matchParams is positional: index i in the config pattern
matches params[i] in the request. Matching is recursive: map patterns require all keys to match,
array patterns require equal length then per-element matching, string patterns use WildcardMatch,
and other types are converted to strings via paramToString (JSON float64 numbers become their
decimal string form: 1234.0 → "1234").
Auth method filter semantics. ignoreMethods is checked first (any match → method blocked),
then allowMethods overrides (any match → force-allowed). Same semantics at upstream, project,
and auth-strategy scopes.
Rate-limit rules. GetRulesByMethod returns all rules whose method pattern matches — not
just the first. Multiple rules can simultaneously consume token-bucket permits for a single request.
Config schema
The matcher engine has no dedicated config block. The table below covers every config field
matched via WildcardMatch, MatchesSelector, SelectExecutor, or MatchFinalities, grouped by
subsystem.
Failsafe — *.failsafe[] (networks, upstreamDefaults, upstreams, networkDefaults, and cache
connector failsafeForGets[]/failsafeForSets[])
| Field | Type | Default | Behavior / footguns |
|---|---|---|---|
matchMethod | string | "*" (set by SetDefaults when empty) | WildcardMatch against the request's JSON-RPC method. Empty is rejected by Validate(). During defaults inheritance, a default's matchMethod is glob-matched against the entry's matchMethod to select which default to apply. Source: common/config.go:L1280, common/defaults.go:L2131-2137 |
matchFinality | []DataFinalityState | [] (empty = any finality) | Exact set-membership check at dispatch time: slices.Contains(list, finality). Empty list = catch-all finality tier. No wildcard inside the list — each element must be an exact finality name. Source: common/config.go:L1281, common/match.go:L38-41 |
matchCommitment | []string | [] (empty = any commitment) | Network scope only: first-match filter, AND-ed with method/finality/kind. Upstream-scope entries that set it fail startup. Values none|processed|confirmed|finalized, OR-ed, exact match (confirmed does not match processed). Compares the commitment erpc pins on the wire: the caller's value, else the svm.commitment default injection writes, else none. Non-SVM requests and SVM write methods (sendTransaction, simulateTransaction, requestAirdrop) are none. Source: common/config.go, architecture/svm/hooks.go, erpc/networks.go |
Cache policies — database.evmJsonRpcCache.policies[]
| Field | Type | Default | Behavior / footguns |
|---|---|---|---|
network | string | "*" (set by SetDefaults) | WildcardMatch against the network ID (e.g., "evm:1", "evm:*"). Source: common/config.go:L320, data/cache_policy.go:L67 |
method | string | "*" (set by SetDefaults) | WildcardMatch against the JSON-RPC method. Source: common/config.go:L321, data/cache_policy.go:L75 |
params | []interface | nil (nil = match any params) | Positional param matching; strings use WildcardMatch. Maps/arrays matched recursively. Non-string types converted via paramToString. Source: common/config.go:L322, data/cache_policy.go:L166-232 |
finality | DataFinalityState | finalized (zero value = 0) | For MatchesForSet: exact equality. For MatchesForGet: finalized requests also match unfinalized policies; unknown finality matches any policy. Footgun: omitting finality yields a finalized-only policy silently. Source: common/config.go:L323, data/cache_policy.go:L99-150 |
Rate-limit rules — rateLimiters.budgets[].rules[]
| Field | Type | Default | Behavior / footguns |
|---|---|---|---|
method | string | required | WildcardMatch against request method. ALL matching rules are returned (not just first) — each independently consumes a token-bucket permit. Source: common/config.go:L1811, upstream/ratelimiter_budget.go:L63-78 |
Upstream method filters — upstreams[], projects[], auth.strategies[]
| Field | Type | Default | Behavior / footguns |
|---|---|---|---|
ignoreMethods | []string | nil | WildcardMatch per entry; any match → method reported unsupported. Applied before allowMethods. Source: common/config.go:L731, upstream/upstream.go:L1375-1385 |
allowMethods | []string | nil | WildcardMatch per entry; any match → overrides an ignoreMethods hit. To allow only eth_getLogs: set ignoreMethods: ["*"], allowMethods: ["eth_getLogs"]. Source: common/config.go:L732, upstream/upstream.go:L1388-1399 |
CORS, aliasing, headers, selectors
| Field | Type | Default | Behavior / footguns |
|---|---|---|---|
projects[].cors.allowedOrigins[] | []string | ["*"] | WildcardMatch against Origin header; first match allows. Source: erpc/http_server.go:L1024 |
server.aliasing.rules[].matchDomain | string | — | WildcardMatch against Host header (port stripped); first rule match wins. Source: common/config.go:L258, erpc/http_server.go:L244-257 |
projects[].forwardHeaders[] | []string | nil | WildcardMatch against incoming header names; matching headers forwarded to upstreams. Source: common/config.go:L519, erpc/http_server.go:L480-493 |
upstreams[].id | string | — | Primary identity matched by MatchesSelector against use-upstream directive value. Source: common/matcher.go:L106-112 |
upstreams[].tags[] | []string | nil | Secondary match by MatchesSelector if id didn't match and pattern has no !. Source: common/matcher.go:L73-100 |
Score multipliers — upstreams[].routing.scoreMultipliers[]
| Field | Type | Default | Behavior / footguns |
|---|---|---|---|
network | string | "" (empty = any) | WildcardMatch against network ID. Source: common/config.go:L798 |
method | string | "" (empty = any) | WildcardMatch against method. Source: common/config.go:L799 |
finality | []DataFinalityState | [] (any) | slices.Contains check. Source: common/config.go:L800 |
Tracing force-trace matchers — tracing.forceTraceMatchers[]
| Field | Type | Default | Behavior / footguns |
|---|---|---|---|
network | string | "" (absent = any) | WildcardMatch against network ID. Both network AND method must match. Source: common/config.go:L241, common/tracing_core.go:L306-329 |
method | string | "" (absent = any) | WildcardMatch against method. Source: common/config.go:L245 |
Served-tip guaranteed methods — networks[].evm.servedTip.guaranteedMethods[]
| Field | Type | Default | Behavior / footguns |
|---|---|---|---|
networks[].evm.servedTip.guaranteedMethods[] | []string | — | Each element validated by ValidatePattern at config load (the only config field with startup validation). At runtime, WildcardMatch against the request method determines whether the served-tip mechanism applies. Source: common/validation.go:L1323-1326 |
Provider network overrides — providers[].overrides (map keys)
| Field | Type | Default | Behavior / footguns |
|---|---|---|---|
providers[].overrides (map key) | string | — | WildcardMatch pattern against network ID. First matching key wins. Source: thirdparty/provider.go:L80-L91 (opens in a new tab) |
Consensus quota tags — consensus/quota.go
Tag membership for quota matching uses WildcardMatch(pattern, t) against each tag string in the upstream config's Tags slice. Source: consensus/quota.go:L96 (opens in a new tab)
Static responses — networks[].staticResponses[] (NOT WildcardMatch)
| Field | Type | Default | Behavior / footguns |
|---|---|---|---|
method | string | required | Exact string equality only — no glob, no boolean operators. "eth_getBlock*" will NOT match eth_getBlockByNumber. Source: common/static_response.go:L16 |
params | []interface | nil (nil = match any params) | Deep equality with numeric-type tolerance (YAML int vs JSON float64). NOT WildcardMatch. Source: common/static_response.go:L19-39 |
DataFinalityState values
| YAML string | Go constant | iota | Meaning |
|---|---|---|---|
"finalized" | DataFinalityStateFinalized | 0 | Block ≤ upstream finalized block. Zero value — omitting finality in config gives this. |
"unfinalized" | DataFinalityStateUnfinalized | 1 | Block known and > upstream finalized block. |
"realtime" | DataFinalityStateRealtime | 2 | Fresh, block-unbound data (e.g., eth_gasPrice). |
"unknown" | DataFinalityStateUnknown | 3 | Block number cannot be determined (trace-by-hash, etc.). |
YAML/JSON accepts string names or their numeric iota indices ("0" = finalized, "1" = unfinalized, "2" = realtime, "3" = unknown).
Source: common/data.go:L8-76
Worked examples
All patterns below are distilled from real production fleets; comments explain the non-obvious choices.
1. Method whitelist on a narrow upstream: block everything, allow only what it indexes.
Production indexing upstreams (e.g. archive nodes, specialized caches) only serve a small
set of methods — blocking everything else avoids wasting a request slot and lets the router
immediately fall to a full-service upstream. This is the canonical ignoreMethods + allowMethods
pattern used on every specialized upstream in the fleet:
upstreams: - id: archive-node # Block all methods on this upstream by default ignoreMethods: - "*" # Then re-allow only the methods this upstream actually serves — anything # else immediately falls to the next upstream without a wasted RTT allowMethods: - "eth_getLogs" - "eth_getBlockByNumber" - "eth_getBlockByHash" - "eth_getBlockReceipts" - "eth_getTransactionByHash" - "eth_getTransactionReceipt"2. Finality-scoped network failsafe: different retry+hedge per finality state.
In production, realtime and unfinalized requests are subject to block-availability races —
a short non-zero delay gives the state-propagation poller time to catch up before retrying.
Finalized requests have no race, so delay: 0 is correct there. At upstream scope the 4-tier
priority resolves conflicts automatically; at network scope, most-specific entries MUST come
first in config order:
failsafe: # Specific method + specific finality wins over all catch-alls (at upstream scope, # this is tier 1 priority; at network scope, place this BEFORE the catch-all) - matchMethod: "eth_call|eth_getLogs" matchFinality: [realtime, unfinalized] retry: maxAttempts: 4 # MUST NOT be 0: a short delay lets block-state propagation catch up before # retrying a "block not available yet" error across another upstream delay: 50ms hedge: delay: quantile: 0.95 min: 500ms max: 10s maxCount: 1 # Same methods, finalized — no block-availability race, so delay: 0 is correct - matchMethod: "eth_call|eth_getLogs" matchFinality: [finalized, unknown] retry: maxAttempts: 4 delay: 0 # Catch-all for everything else — realtime/unfinalized needs the delay too - matchMethod: "*" matchFinality: [realtime, unfinalized] retry: maxAttempts: 6 delay: 50ms - matchMethod: "*" matchFinality: [finalized, unknown] retry: maxAttempts: 6 delay: 03. Per-method upstream timeouts using glob priority.
Production upstream failsafe sets tight timeouts per method tier — heavy methods like
eth_getLogs need a generous ceiling; light point-reads need a tight one to encourage fast
hedging on stuck upstreams. Glob patterns (eth_get*) serve as a catch-all tier, with
more-specific exact entries placed before them. At upstream scope, 4-tier priority handles
the ordering automatically, so explicit placement is not required — but it is still good style:
upstreamDefaults: failsafe: # Exact method entries are tier 2 (method-only) — win over the glob catch-all tier - matchMethod: "eth_getLogs|eth_getBlockReceipts" timeout: # Variable latency tied to range/density — routinely seconds on big queries duration: 15s - matchMethod: "eth_getTransactionReceipt" timeout: duration: 8s - matchMethod: "eth_getBlockByNumber" timeout: # min raised: archive lookups on fast chains (Sei, Monad) can take 350–500ms duration: 3s - matchMethod: "trace_*|debug_*|arbtrace_*" timeout: # Trace methods can be slow — 30s gives them room without blocking others duration: 30s # Glob catch-all for remaining eth_get* light getters — tier 2, wins over "*" - matchMethod: "eth_get*" timeout: duration: 5s # Final catch-all — tier 4, lowest priority - matchMethod: "*" timeout: duration: 60s4. Cache policy with explicit method allowlist and all-finality coverage.
In production, cache policies use a pipe-joined method pattern (|) rather than a broad
glob because eth_get* would flood every connector with requests for methods nothing
serves (eth_getBalance, eth_getCode, eth_getStorageAt, …), paying a connector RTT for
a guaranteed miss. Three finality tiers cover all concrete-block requests; realtime
finality is intentionally excluded so head-tracking queries always hit fresh upstreams:
database:
evmJsonRpcCache:
policies:
# Using | instead of eth_get* avoids cache misses on balance/code/storage methods
- network: "evm:1"
method: "eth_getBlockByNumber|eth_getBlockByHash|eth_getBlockReceipts|eth_getLogs|eth_getTransactionByHash|eth_getTransactionReceipt"
finality: unfinalized
connector: my-cache
- network: "evm:1"
method: "eth_getBlockByNumber|eth_getBlockByHash|eth_getBlockReceipts|eth_getLogs|eth_getTransactionByHash|eth_getTransactionReceipt"
finality: unknown
connector: my-cache
- network: "evm:1"
method: "eth_getBlockByNumber|eth_getBlockByHash|eth_getBlockReceipts|eth_getLogs|eth_getTransactionByHash|eth_getTransactionReceipt"
finality: finalized
connector: my-cache
# realtime deliberately omitted — eth_blockNumber / eth_getBlockByNumber("latest")
# must always hit upstreams so clients see the current chain head5. Per-method rate-limit rules: protect heavy methods without stacking a wildcard.
Heavy-method traffic (eth_getBlockReceipts, trace_*) can exhaust proxy concurrency
when a single user sends high-error-rate bursts, holding a connection per failed attempt.
A method-specific rule caps only that traffic; a separate wildcard rule caps global volume.
Note that ALL matching rules fire simultaneously — if you add a "*" rule AND a specific
rule, a heavy-method request consumes from both buckets:
rateLimiters: budgets: - id: chain-admission rules: # Heavy receipt methods empirically drive proxy-connection stack-ups — cap tightly. # Healthy peak is ~5 RPS total; 100 RPS gives 20× headroom for legitimate spikes - method: "eth_getBlockReceipts|eth_getTransactionReceipt" maxCount: 100 period: 1s # Trace methods have low typical volume; 30 RPS matches observed traffic - method: "debug_*|trace_*|arbtrace_*" maxCount: 30 period: 1s # Global wildcard intentionally omitted here — these two rules are # independent; a request matching both rules debits both bucketsRequest/response behavior
- The
use-upstreamdirective is set via theX-ERPC-Use-Upstreamrequest header or query param. The value is aMatchesSelectorpattern — id first, then tags if no!in pattern. ignoreMethodsandallowMethodsat project or upstream scope cause eRPC to returnErrUpstreamMethodIgnoredfor blocked methods — surfaced to the client as an upstream unsupported error.- Rate-limit rules whose
methodmatches fire simultaneously: a request denied by two matching rules gets a rate-limit error even if only one rule was intended as the effective gate. - A malformed pattern in most config fields silently skips matches at runtime (caller
continue-on-error pattern) — no error is returned to the client; the config field is simply treated as non-matching.
Best practices
- Prefer exact method names or simple globs (
"eth_*","*") on hot paths like failsafematchMethod— complex boolean expressions re-parse on every request with no caching. - At network scope, order failsafe entries from most-specific to least-specific manually — unlike upstream scope, there is no 4-tier priority; the first matching entry wins.
- For rate-limit budgets, remember that all matching rules fire simultaneously — a global
"*"rule and a per-method rule both debit their buckets. Size them with overlap in mind. - Use
ignoreMethods: ["*"]+allowMethods: [...]to build explicit whitelists — it is cleaner and safer than long lists of specific ignore patterns. - For hex numeric comparisons in cache policy params, always also cover named tags with
|:"(latest | safe | finalized) | >=0x1000000"— a value like"latest"has no0xprefix and falls through to glob matching, so numeric-only patterns miss it. - Avoid setting
!inuse-upstreamselector patterns unless you specifically want to suppress tag matching — any!anywhere in the pattern disables tag fallback entirely. - Validate patterns at startup where possible:
ValidatePatternis only automatically called forevm.servedTip.guaranteedMethods; other fields accept invalid patterns silently and fail at runtime.
Edge cases & gotchas
- No escaping for meta-characters.
|,&,!,(,)cannot appear as literal values in a pattern. A method name likenet_!customis untestable viaWildcardMatch. Source:common/matcher.go:L226-258 - Spaces are atom separators.
"eth_getLogs "(trailing space) tokenizes as["eth_getLogs"]. A pattern intended to match a literal space will silently split into two tokens. Source:common/matcher.go:L229-260 - Numeric operators require
0xprefix on the runtime value.>100against value"200"does NOT compare numerically — it falls through to glob. Use hex-prefixed values ("0x64"= 100) to enable numeric comparison. Source:common/matcher.go:L373-391 - Hex overflow at
0x7FFFFFFFFFFFFFFF.parseNumberusesstrconv.ParseInt(s, 16, 64)— values above signed 64-bit max parse silently as errors andcompareNumbersreturnsfalse. Source:common/matcher.go:L399-438 MatchesSelectornegation guard is coarse. Any!anywhere in the pattern — even"!other-upstream"— disables tag matching entirely. This is by design: a tag match must not rescue an excluded upstream. Source:common/matcher.go:L87-89- Network-level vs upstream-level failsafe selection differ. Upstream uses 4-tier priority; network uses config-order first-match. Same field names, different semantics. Source:
upstream/upstream.go:L372-408,erpc/networks.go:L910-928 matchFinality: []is catch-all at dispatch, butMatchFinalitiesempty-means-any is only for defaults merging. Two different functions handle the same field in different contexts. Source:common/defaults.go:L17-34,common/match.go:L38-41- Static response
methodis exact equality, not wildcard. Unlike every other string matcher,FindStaticResponseMatchuses byte equality. A glob pattern instaticResponses[].methodis silently treated as a literal string. Source:common/static_response.go:L16 CachePolicyConfig.finalityzero-value isfinalized. Omittingfinalityin a cache policy gives a finalized-only policy without any warning. Source:common/data.go:L15- Multiple rate-limit rules fire simultaneously. All rules whose
methodpattern matches are returned and each independently debits a token bucket. A single request may be throttled by a"*"rule and a specific-method rule at the same time. Source:upstream/ratelimiter_budget.go:L63-78 ValidatePatternis called only forevm.servedTip.guaranteedMethodsat startup. Other pattern fields (cache policy method, failsafe matchMethod, etc.) are not validated at config load — an invalid pattern silently skips matches at runtime. Source:common/validation.go:L1323-1326WildcardMatchconcurrent calls are safe (no shared mutable state per call) butRateLimiterBudget.GetRulesByMethodholds async.RWMutexduring iteration. Re-tokenization cost is paid under the read lock on every matching call. Source:upstream/ratelimiter_budget.go:L63-78paramToStringon float64 from JSON. JSON numbers decode asfloat64;strconv.FormatFloat(v, 'f', -1, 64)produces"1234"not"1234.0". A string pattern"123*"would match numeric param1234. Source:data/cache_policy.go:L234-249- Cache
MatchesForGetreturnstrueforunknownfinality across all policies. A request with indeterminate finality can be served from afinalizedpolicy's cache, potentially returning stale data. Source:data/cache_policy.go:L146-149 - Legacy single-object failsafe migration is silent. An old
failsafe: {…}(object form) is quietly converted to a 1-element slice. No log or warning is emitted. The migration only forcesmatchMethodto"*"when the field is empty — an explicitly-set non-emptymatchMethodvalue (e.g.,"eth_call") is preserved as-is. The migration applies at YAML parse time acrossNetworkConfig,NetworkDefaults, andUpstreamConfig. Source:common/config.go:L2041-2103 - Zero-config auto-generated project only when
projects:is entirely absent. Evenprojects: []skips the auto-generated 'main' project defaults. Source:common/defaults.go:L100-167 DataFinalityStateAll = -1is an internal sentinel. It must never appear in config or on requests — it only lives in health-tracker cross-finality rollup keys. Source:common/data.go:L29-36- Empty pattern in
MatchesSelectoralways returnsfalse. The function guards against empty patterns at entry and immediately returnsfalse. Callers must ensure theuse-upstreamdirective value is non-empty — an emptyX-ERPC-Use-Upstreamheader or query param results in no upstream being selected by that directive. Source:common/matcher.go:L73
Observability
| Metric | Type | Labels | When it fires |
|---|---|---|---|
erpc_unexpected_panic_total{scope="validate-pattern"} | counter | scope, extra (pattern), error | ValidatePattern catches a tokenizer/parser panic |
erpc_network_static_response_served_total | counter | project, network, method | Every static-response cache hit in tryServeStaticResponse |
Trace span attributes set during network-level failsafe selection:
failsafe.matched_method— the matchedmatchMethodvaluefailsafe.matched_finalities— the matched finality list
Source: erpc/networks.go:L1179-1180
Notable log lines:
"method support result"— Debug,upstream/upstream.go, fields:allowed(bool),method(string). Emitted after each upstream method-support check."skipping static response: cannot inspect request"— Debug,erpc/networks_static_responses.go. Emitted when params cannot be read for static-response matching."served static response (no upstream contacted)"— Debug,erpc/networks_static_responses.go. Emitted on a static-response cache hit."error matching ignore method … with method …"— Error,auth/authorizer.go. Emitted whenWildcardMatchreturns an error during auth method-filter evaluation.
Source code entry points
common/matcher.go:L221-L272(opens in a new tab) —tokenize: byte-by-byte tokenizer producingtokenOr,tokenAnd,tokenNot,tokenLParen,tokenRParen,tokenPatterncommon/matcher.go:L73-L134(opens in a new tab) —MatchesSelector,UpstreamMatchesSelector,ValidatePatterncommon/match.go:L18-L78(opens in a new tab) —SelectExecutor[E]: generic 4-tier executor picker (single pass, four tier buckets)data/cache_policy.go:L62-L249(opens in a new tab) —MatchesForSet,MatchesForGet,matchParams,matchParam,paramToStringcommon/static_response.go:L14-L39(opens in a new tab) —FindStaticResponseMatch: exact-equality path (distinct fromWildcardMatch)common/defaults.go:L17-L34(opens in a new tab) —MatchFinalities: set-overlap utility used only in defaults mergingupstream/upstream.go:L372-L408(opens in a new tab) — upstream-levelgetFailsafeExecutor: manual 4-tier looperpc/networks.go:L910-L928(opens in a new tab) — network-levelgetFailsafeExecutor: config-order first-match scanauth/authorizer.go:L80-L115(opens in a new tab) —shouldApplyToMethod: ignore-then-allow semanticsconsensus/quota.go:L96(opens in a new tab) —WildcardMatchon upstream tag strings for consensus quota matchingcommon/matcher_test.go(opens in a new tab) — comprehensive table-driven tests forWildcardMatch,MatchesSelector,ValidatePattern
Related pages
- Failsafe — uses
matchMethod+matchFinalityfor executor dispatch. - Rate limiters — uses
methodpattern; all matching rules fire simultaneously. - Auth — uses
ignoreMethods/allowMethodswith same ignore-then-allow semantics. - Database / cache — uses
network,method, andparamspatterns in policies. - Projects — project-level
ignoreMethods/allowMethodsandforwardHeaderspatterns.