Commit a921174
[TT-16767][Global] [Implementation] Centralised Error Overrides Infrastructure (#7867)
<!-- Provide a general summary of your changes in the Title above -->
## Description
This PR introduces a centralized Error Overrides feature, allowing for
the customization of error responses at the gateway level. This
functionality enables users to standardize error formats, hide internal
error details, and provide branded or localized messages for both
gateway-generated errors (e.g., auth failures, rate limits) and upstream
service errors (e.g., 4xx/5xx responses).
The implementation is optimized for performance, featuring a near-zero
overhead path when no overrides are configured. All matching rules,
including regular expressions and inline templates, are pre-compiled at
gateway startup to ensure minimal latency during error handling.
<!-- Describe your changes in detail -->
# Error Override Performance Benchmarks
## Executive Summary
The error override feature adds **negligible performance overhead** to
the error handling path:
- **No overrides configured**: ~5 ns/op overhead (fast path with map
length check)
- **Direct message override**: ~5.8 μs/op vs ~11.1 μs/op baseline (48%
**faster** than default template)
- **With template execution**: ~7-11 μs/op (comparable to or faster than
default template rendering)
**Optimization:** The code checks if overrides exist before entering the
override path, ensuring minimal impact on existing deployments.
## Detailed Results
### 1. ApplyOverride - Matching Performance
Testing the core matching logic that determines if an override should be
applied:
```
BenchmarkApplyOverride/no_overrides_configured 4.05 ns/op 0 B/op 0 allocs/op
BenchmarkApplyOverride/exact_code_match 55.0 ns/op 32 B/op 1 allocs/op
BenchmarkApplyOverride/pattern_match_4xx 66.2 ns/op 32 B/op 1 allocs/op
BenchmarkApplyOverride/regex_pattern_match 219.8 ns/op 32 B/op 1 allocs/op
BenchmarkApplyOverride/regex_pattern_non-match 169.8 ns/op 0 B/op 0 allocs/op
BenchmarkApplyOverride/JSON_body_field_match 226.9 ns/op 48 B/op 2 allocs/op
BenchmarkApplyOverride/multiple_rules_-_first_match 235.5 ns/op 32 B/op 1 allocs/op
```
**Key Findings:**
- **No configuration**: ~4 ns overhead - very low
- **Exact code match**: ~55 ns (O(1) hash map lookup)
- **Pattern match** (4xx/5xx): ~66 ns (prefix calculation + map lookup)
- **Regex matching**: ~220 ns (compiled regex)
- **JSON path matching**: ~227 ns (gjson library)
### 2. Flag-Based Matching (Error Classification)
Flag matching uses the error classification system for semantic matching
- matching by error *type* rather than text patterns:
```
BenchmarkApplyOverride/flag_match_-_exact_match 92.9 ns/op 32 B/op 1 allocs/op
BenchmarkApplyOverride/flag_match_-_no_classification 26.8 ns/op 0 B/op 0 allocs/op
BenchmarkApplyOverride/flag_match_-_fallback_to_regex 193.9 ns/op 32 B/op 1 allocs/op
BenchmarkApplyOverride/multiple_flag_rules_-_first_match 104.7 ns/op 32 B/op 1 allocs/op
BenchmarkApplyOverride/multiple_flag_rules_-_catch_all 110.7 ns/op 32 B/op 1 allocs/op
```
**Flag vs Regex Performance Comparison:**
```
BenchmarkApplyOverride/flag_vs_regex_-_flag 75.1 ns/op 32 B/op 1 allocs/op
BenchmarkApplyOverride/flag_vs_regex_-_regex 173.2 ns/op 0 B/op 0 allocs/op
```
**Key Findings:**
- **Flag matching is ~2.3x faster than regex** (75 ns vs 173 ns)
- **No classification in context**: 26.8 ns (very fast early exit)
- **Multiple flag rules**: ~105-111 ns (efficient even with multiple
rules)
- **Fallback to regex**: ~194 ns (checks flag first, then regex)
- Flag matching is a simple string comparison vs regex execution
### 3. WriteOverrideResponse vs WriteTemplateErrorResponse
Direct comparison of error response writing:
```
Response Method Time Memory Allocs
--------------------------------------------------------------------------------------
BenchmarkWriteOverrideResponse/direct_message 5.8 μs 7312 B 31 allocs
BenchmarkWriteOverrideResponse/inline_template_JSON 9.5 μs 7745 B 49 allocs
BenchmarkWriteOverrideResponse/inline_template_XML 7.4 μs 7513 B 38 allocs
BenchmarkWriteOverrideResponse/file_template_JSON 10.2 μs 8001 B 51 allocs
BenchmarkWriteOverrideResponse/file_template_XML 7.7 μs 7769 B 40 allocs
BenchmarkWriteOverrideResponse/with_custom_headers 11.1 μs 8537 B 67 allocs
BenchmarkWriteTemplateErrorResponse/default_JSON 11.1 μs 7532 B 41 allocs
```
**Key Findings:**
- **Direct message writing**: 5.8 μs - **48% faster** than default
template (11.1 μs)
- Best performance when no templating needed
- Writes JSON/XML response directly
- **Inline template**: 7.4-9.5 μs - Also faster than default
- Allows dynamic {{.StatusCode}} and {{.Message}} substitution
- Very efficient
- **File template**: 7.7-10.2 μs - Within acceptable range
- Reuses existing template infrastructure
- Performance varies by template complexity
### 4. Compilation Performance
One-time cost during gateway startup or API reload:
```
BenchmarkCompileErrorOverrides/single_exact_code 0.76 μs 520 B 6 allocs
BenchmarkCompileErrorOverrides/multiple_exact_codes 1.67 μs 1000 B 14 allocs
BenchmarkCompileErrorOverrides/with_regex_patterns 0.76 μs 624 B 6 allocs
BenchmarkCompileErrorOverrides/with_inline_templates 12.23 μs 8240 B 99 allocs
BenchmarkCompileErrorOverrides/mixed_exact_and_patterns 2.01 μs 1374 B 17 allocs
```
**Key Findings:**
- Simple configurations compile in ~0.8-2 μs
- Regex compilation adds minimal overhead
- Template compilation is more expensive (~12 μs) but happens only at
startup
- All costs are one-time during configuration load
## Fast Path Optimization
Testing the entry point `tryWriteOverride` with empty vs configured
overrides:
```
BenchmarkTryWriteOverride/empty_config_-_fast_path 5.14 ns/op 0 B/op 0 allocs/op
BenchmarkTryWriteOverride/config_exists_-_match_with_direct_body 2450 ns/op 1824 B/op 22 allocs/op
```
**Key Findings:**
- The optimization checks `len(e.Spec.GlobalConfig.ErrorOverrides) == 0`
before proceeding
- When empty (no overrides configured), returns immediately without
atomic loads
- Fast path overhead: ~5 ns with zero allocations
- This is **476x faster** than processing a match (~2.5 μs)
- This is **43x faster** than a regex match (~220 ns)
## Performance Impact Analysis
### Hot Path (Every Error Response)
When **no overrides are configured** (most common case):
- Overhead: **~5 ns** per error (fast path with map length check)
- Memory: 0 bytes allocated
- **Impact: Virtually zero** - immeasurable in real-world operations
When **overrides are configured and match**:
- Best case (direct message): **48% faster** than default template
- Typical case (inline template): ~15-33% faster than default
- Worst case (file template JSON): ~10 μs (comparable to default)
### Cold Path (Gateway Startup)
Compilation happens once during:
- Gateway initialization
- API configuration reload
- Overhead: ~0.8-12 μs depending on complexity
- **Impact: Negligible** - happens infrequently
## Memory Allocation Analysis
Memory allocations per error response:
```
Operation Allocations Bytes
----------------------------------------------------
No override check 0 allocs 0 B
Exact code match 1 alloc 32 B
Pattern match (4xx/5xx) 1 alloc 32 B
Flag match (exact) 1 alloc 32 B
Flag match (no classification) 0 allocs 0 B
Regex pattern match 1 alloc 32 B
Direct message write 31 allocs 7312 B
Inline template execution 49 allocs 7745 B
Default template 41 allocs 7532 B
```
**Key Findings:**
- Zero allocations when no overrides configured
- Zero allocations for flag match when no classification in context
- Minimal allocation (32B) for matching logic
- Direct message writing uses similar memory to default template
- No memory leaks or unbounded allocations
## Scalability Considerations
### Large Body Handling
```
BenchmarkApplyOverride/large_body_truncation 1.28 μs 538 B 6 allocs
```
- Large bodies (>4KB) are truncated before pattern matching
- Prevents performance degradation with large error responses
- Adds ~1.3 μs overhead only when bodies exceed 4KB
### Multiple Rules
```
BenchmarkApplyOverride/multiple_rules_-_first_match 236 ns 32 B/op 1 allocs
```
- First-match semantics ensure O(n) worst case
- In practice, most errors match within 1-2 rules
- No performance degradation with reasonable rule counts
## Conclusions
**Virtually zero overhead when disabled**: ~5 ns (fast path with map
length check) - immeasurable in production
**Optimized check path**: Early exit when no overrides configured
prevents significant overhead
**Status code matching is fast**: Both exact (~55 ns) and pattern (~66
ns) matching are very efficient
**Flag matching is ~2.3x faster than regex**: 75 ns vs 173 ns for
semantic error matching
**Faster for simple overrides**: Direct message writing is 48% faster
than default templates
**Acceptable overhead for advanced features**: Template execution adds
reasonable overhead for the flexibility gained
**Efficient matching**: O(1) lookups for exact codes, fast flag
comparison, pre-compiled regex
**No memory leaks**: Bounded allocations, pre-compiled patterns
## Recommendations
For **best performance**:
1. Use flag-based matching when possible (~2.3x faster than regex)
2. Use direct message writing (no template variables) when possible
3. Keep regex patterns simple
4. Pre-compile overrides at startup (already implemented)
For **optimal flexibility**:
1. Use flag matching for semantic error types (e.g., `RLT` for rate
limiting)
2. Use inline templates with {{.StatusCode}} and {{.Message}}
3. Use file templates for complex responses
4. Use JSON body field matching for structured upstream error responses
5. Use regex patterns as fallback when flag classification isn't
available
6. Both exact and pattern (4xx/5xx) status code matching are efficient
(~55-66 ns)
---
**Test Environment:**
- Machine: Apple M1 Pro
- Go Version: 1.25.1
- OS: macOS (darwin/arm64)
- Benchmark Duration: 3 seconds per benchmark
## Related Issue
<!-- This project only accepts pull requests related to open issues. -->
<!-- If suggesting a new feature or change, please discuss it in an
issue first. -->
<!-- If fixing a bug, there should be an issue describing it with steps
to reproduce. -->
<!-- OSS: Please link to the issue here. Tyk: please create/link the
JIRA ticket. -->
## Motivation and Context
<!-- Why is this change required? What problem does it solve? -->
## How This Has Been Tested
<!-- Please describe in detail how you tested your changes -->
<!-- Include details of your testing environment, and the tests -->
<!-- you ran to see how your change affects other areas of the code,
etc. -->
<!-- This information is helpful for reviewers and QA. -->
## Screenshots (if appropriate)
## Types of changes
<!-- What types of changes does your code introduce? Put an `x` in all
the boxes that apply: -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Refactoring or add test (improvements in base code or adds test
coverage to functionality)
## Checklist
<!-- Go over all the following points, and put an `x` in all the boxes
that apply -->
<!-- If there are no documentation updates required, mark the item as
checked. -->
<!-- Raise up any additional concerns not covered by the checklist. -->
- [ ] I ensured that the documentation is up to date
- [ ] I explained why this PR updates go.mod in detail with reasoning
why it's required
- [ ] I would like a code coverage CI quality gate exception and have
explained why
<!---TykTechnologies/jira-linter starts here-->
### Ticket Details
<details>
<summary>
<a href="https://tyktech.atlassian.net/browse/TT-16767" title="TT-16767"
target="_blank">TT-16767</a>
</summary>
| | |
|---------|----|
| Status | Ready for Testing |
| Summary | [1a] Implement Centralised Error Overrides Infrastructure |
Generated at: 2026-03-17 16:11:43
</details>
<!---TykTechnologies/jira-linter ends here-->
---------
Co-authored-by: Edson Michaque <edson@michaque.com>
Co-authored-by: andyo-tyk <99968932+andyo-tyk@users.noreply.github.com>
Co-authored-by: Vlad Zabolotnyi <109525963+vladzabolotnyi@users.noreply.github.com>
Co-authored-by: Vlad Zabolotnyi <vlad.z@tyk.io>
Co-authored-by: Leonid Bugaev <leonsbox@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: andrei-tyk <97896463+andrei-tyk@users.noreply.github.com>
Co-authored-by: Laurentiu <6229829+lghiur@users.noreply.github.com>
Co-authored-by: Burak Sezer <burak.sezer.developer@gmail.com>1 parent 9792d07 commit a921174
File tree
97 files changed
+13583
-27
lines changed- apidef
- oas
- schema
- streams/schema
- ci/tests/error-overrides
- apps
- configs
- policies
- scripts
- templates
- cli/linter
- config
- gateway
- internal/errors
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
97 files changed
+13583
-27
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
792 | 792 | | |
793 | 793 | | |
794 | 794 | | |
| 795 | + | |
| 796 | + | |
| 797 | + | |
| 798 | + | |
795 | 799 | | |
796 | 800 | | |
797 | 801 | | |
| |||
1601 | 1605 | | |
1602 | 1606 | | |
1603 | 1607 | | |
| 1608 | + | |
| 1609 | + | |
| 1610 | + | |
| 1611 | + | |
| 1612 | + | |
| 1613 | + | |
| 1614 | + | |
| 1615 | + | |
| 1616 | + | |
| 1617 | + | |
| 1618 | + | |
| 1619 | + | |
| 1620 | + | |
| 1621 | + | |
| 1622 | + | |
| 1623 | + | |
| 1624 | + | |
| 1625 | + | |
| 1626 | + | |
| 1627 | + | |
1604 | 1628 | | |
1605 | 1629 | | |
1606 | 1630 | | |
| |||
1632 | 1656 | | |
1633 | 1657 | | |
1634 | 1658 | | |
1635 | | - | |
1636 | | - | |
1637 | | - | |
| 1659 | + | |
| 1660 | + | |
| 1661 | + | |
| 1662 | + | |
1638 | 1663 | | |
1639 | 1664 | | |
1640 | 1665 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| 10 | + | |
10 | 11 | | |
| 12 | + | |
11 | 13 | | |
12 | 14 | | |
13 | 15 | | |
| |||
718 | 720 | | |
719 | 721 | | |
720 | 722 | | |
| 723 | + | |
| 724 | + | |
| 725 | + | |
| 726 | + | |
| 727 | + | |
| 728 | + | |
| 729 | + | |
| 730 | + | |
| 731 | + | |
| 732 | + | |
| 733 | + | |
| 734 | + | |
| 735 | + | |
| 736 | + | |
| 737 | + | |
| 738 | + | |
| 739 | + | |
| 740 | + | |
| 741 | + | |
| 742 | + | |
| 743 | + | |
| 744 | + | |
| 745 | + | |
| 746 | + | |
| 747 | + | |
| 748 | + | |
| 749 | + | |
| 750 | + | |
| 751 | + | |
| 752 | + | |
| 753 | + | |
| 754 | + | |
| 755 | + | |
| 756 | + | |
| 757 | + | |
| 758 | + | |
| 759 | + | |
| 760 | + | |
| 761 | + | |
| 762 | + | |
| 763 | + | |
| 764 | + | |
| 765 | + | |
| 766 | + | |
| 767 | + | |
| 768 | + | |
| 769 | + | |
| 770 | + | |
| 771 | + | |
| 772 | + | |
| 773 | + | |
| 774 | + | |
| 775 | + | |
| 776 | + | |
| 777 | + | |
| 778 | + | |
| 779 | + | |
| 780 | + | |
| 781 | + | |
| 782 | + | |
| 783 | + | |
| 784 | + | |
| 785 | + | |
| 786 | + | |
| 787 | + | |
| 788 | + | |
| 789 | + | |
| 790 | + | |
| 791 | + | |
| 792 | + | |
| 793 | + | |
| 794 | + | |
| 795 | + | |
| 796 | + | |
| 797 | + | |
| 798 | + | |
| 799 | + | |
| 800 | + | |
| 801 | + | |
| 802 | + | |
| 803 | + | |
| 804 | + | |
| 805 | + | |
| 806 | + | |
| 807 | + | |
| 808 | + | |
| 809 | + | |
| 810 | + | |
| 811 | + | |
| 812 | + | |
| 813 | + | |
| 814 | + | |
| 815 | + | |
| 816 | + | |
| 817 | + | |
| 818 | + | |
| 819 | + | |
| 820 | + | |
| 821 | + | |
| 822 | + | |
| 823 | + | |
| 824 | + | |
| 825 | + | |
| 826 | + | |
| 827 | + | |
| 828 | + | |
| 829 | + | |
| 830 | + | |
| 831 | + | |
| 832 | + | |
| 833 | + | |
| 834 | + | |
| 835 | + | |
| 836 | + | |
| 837 | + | |
| 838 | + | |
| 839 | + | |
| 840 | + | |
| 841 | + | |
| 842 | + | |
| 843 | + | |
| 844 | + | |
| 845 | + | |
| 846 | + | |
| 847 | + | |
| 848 | + | |
| 849 | + | |
| 850 | + | |
| 851 | + | |
| 852 | + | |
| 853 | + | |
| 854 | + | |
| 855 | + | |
| 856 | + | |
| 857 | + | |
| 858 | + | |
| 859 | + | |
| 860 | + | |
| 861 | + | |
| 862 | + | |
| 863 | + | |
| 864 | + | |
| 865 | + | |
| 866 | + | |
| 867 | + | |
| 868 | + | |
| 869 | + | |
| 870 | + | |
| 871 | + | |
| 872 | + | |
| 873 | + | |
| 874 | + | |
| 875 | + | |
| 876 | + | |
| 877 | + | |
| 878 | + | |
| 879 | + | |
| 880 | + | |
| 881 | + | |
| 882 | + | |
| 883 | + | |
| 884 | + | |
| 885 | + | |
| 886 | + | |
| 887 | + | |
| 888 | + | |
| 889 | + | |
| 890 | + | |
| 891 | + | |
| 892 | + | |
| 893 | + | |
| 894 | + | |
| 895 | + | |
| 896 | + | |
| 897 | + | |
| 898 | + | |
| 899 | + | |
| 900 | + | |
| 901 | + | |
| 902 | + | |
| 903 | + | |
| 904 | + | |
| 905 | + | |
| 906 | + | |
| 907 | + | |
| 908 | + | |
| 909 | + | |
| 910 | + | |
| 911 | + | |
| 912 | + | |
| 913 | + | |
| 914 | + | |
| 915 | + | |
| 916 | + | |
| 917 | + | |
| 918 | + | |
| 919 | + | |
| 920 | + | |
| 921 | + | |
| 922 | + | |
| 923 | + | |
| 924 | + | |
| 925 | + | |
| 926 | + | |
| 927 | + | |
| 928 | + | |
| 929 | + | |
| 930 | + | |
| 931 | + | |
| 932 | + | |
| 933 | + | |
| 934 | + | |
| 935 | + | |
| 936 | + | |
| 937 | + | |
| 938 | + | |
| 939 | + | |
| 940 | + | |
| 941 | + | |
| 942 | + | |
| 943 | + | |
| 944 | + | |
| 945 | + | |
| 946 | + | |
| 947 | + | |
| 948 | + | |
| 949 | + | |
| 950 | + | |
| 951 | + | |
| 952 | + | |
| 953 | + | |
| 954 | + | |
| 955 | + | |
| 956 | + | |
| 957 | + | |
| 958 | + | |
| 959 | + | |
| 960 | + | |
| 961 | + | |
| 962 | + | |
| 963 | + | |
| 964 | + | |
| 965 | + | |
| 966 | + | |
| 967 | + | |
| 968 | + | |
| 969 | + | |
| 970 | + | |
| 971 | + | |
| 972 | + | |
| 973 | + | |
| 974 | + | |
721 | 975 | | |
722 | 976 | | |
723 | 977 | | |
| |||
0 commit comments