A tool for checking whether the error argument passed to CheckDeletedDiag method in Terraform Provider code has been formatted. Formatting errors corrupts the original error type, preventing effective error recognition.
checkdeleted-input-errors-formating/
├── check_error_format.py # Main entry point
├── README.md # Documentation
├── LICENSE # License
├── .github/ # GitHub Actions workflows
│ └── workflows/
│ └── check-error-format.yml
├── tools/ # Tool scripts directory
│ ├── en-us/ # English tool scripts
│ │ └── quick_install.sh # Quick install script (English)
│ └── zh-cn/ # Chinese tool scripts
│ └── quick_install.sh # Quick install script (Chinese)
└── rules/ # Rules directory
├── __init__.py
├── base_rule.py # Base rule class
└── cq_rules/ # Code quality rules
├── __init__.py
├── rule_001.py # CQ.001 rule implementation
├── go_ast_parser.go # Go AST parser source code
└── go_ast_parser # Compiled Go AST parser executable
The project adopts a rule-based architecture, where each code quality rule is an independent class:
- Base Rule Class (
rules/base_rule.py): Defines the interface that all rules must implement - CQ.001 Rule (
rules/cq_rules/rule_001.py): Checks whether the error parameter of the CheckDeletedDiag method is formatted
This rule checks whether the error parameter used by the common.CheckDeletedDiag method in Terraform Provider code is formatted. If the error parameter is formatted (e.g., using fmt.Errorf), it will corrupt the original error type, causing the method to fail to effectively recognize the error content.
Detection Scope:
- Only checks
CheckDeletedDiagcalls withinReadContextmethods (functions matchingresourceXXXReadordataSourceXXXReadpattern) - Ignores calls in other methods like
DeleteContext,CreateContext, etc.
Detection Logic:
- Traces the error variable from
CheckDeletedDiagcall back to its source function - Verifies that the error actually reaches
CheckDeletedDiag(not handled viadiag.FromErrordiag.Errorfearlier) - Checks if the source function formats the error using
fmt.Errorfor similar patterns
In Terraform Provider code, the common.CheckDeletedDiag method is used to check whether a resource has been deleted. If the error parameter passed in is formatted (e.g., using fmt.Errorf), it will corrupt the original error type, causing the method to fail to effectively recognize the error content (e.g., 404 errors).
The tool provides:
- Accurate Function Extraction: Uses Go AST parser for robust function definition extraction
- Error Flow Tracing: Traces error variables from
CheckDeletedDiagcalls back to their source functions - False Positive Prevention: Verifies errors actually reach
CheckDeletedDiagand filters out errors handled earlier - Context-Aware Detection: Only checks
ReadContextmethods, ignoring other contexts - High Performance: Parallel processing with file caching for fast analysis of large codebases
- Progress Control: Optional progress output for debugging and monitoring
error-format-check -d <directory_or_file> [-p <true|false>]-d, --directory <directory_or_file>: Target directory or Go file to check (required)-p, --process <true|false>: Whether to show progress information (default:false)-h, --help: Show help message and exit
Use the one-click installation script to quickly deploy the tool locally:
English Version:
curl -fsSL https://raw.githubusercontent.com/chnsz/checkdeleted-input-errors-formating/master/tools/en-us/quick_install.sh | bashChinese Version:
curl -fsSL https://raw.githubusercontent.com/chnsz/checkdeleted-input-errors-formating/master/tools/zh-cn/quick_install.sh | bashAfter installation, the tool will be installed to ~/.local/bin/error-format-check and the PATH environment variable will be automatically configured.
Note: If the command is not available after installation, run source ~/.bashrc (or source ~/.zshrc) to refresh the environment variables, or reopen the terminal.
Basic usage (silent mode, default):
error-format-check -d /path/to/terraform-provider-huaweicloud
error-format-check -d ./huaweicloud/services/fgs
error-format-check -d /path/to/file.goWith progress output:
error-format-check -d /path/to/dir -p trueShow help:
error-format-check --helpIf you need to install manually:
- Clone the repository:
git clone https://github.com/chnsz/checkdeleted-input-errors-formating.git
cd checkdeleted-input-errors-formating- Build Go AST parser (optional but recommended):
cd rules/cq_rules
go build -o go_ast_parser go_ast_parser.go
cd ../..- Run the tool:
python3 check_error_format.py -d <directory_or_file> [-p <true|false>]Note: If the Go AST parser is not available, the tool will automatically fall back to regex-based function extraction.
The tool can be run in GitHub Actions workflows.
For integrating this tool into other repositories, see:
For publishing to GitHub Actions Marketplace, see:
For examples in this repository, see .github/workflows/check-error-format.yml.
Using as a GitHub Action (once published to Marketplace):
- name: Check Error Format
uses: chnsz/[email protected]
with:
directory: '.'
show-progress: 'false'The workflow:
- Automatically builds the Go AST parser
- Runs the check on the target repository
- Only fails if there are tool execution errors (compilation/syntax errors)
- Succeeds even if issues are found (displays results without failing the workflow)
When issues are found, the tool will output:
================================================================================
ERROR - Issues found:
================================================================================
Error - <relative_file_path> (line <line_number>): Formatting the `error` argument of the `CheckDeleted` method is prohibited. It will corrupt the original error type, causing the method to fail to effectively recognize the error content.
Total: <count> issue(s) found
When no issues are found (with -p true):
✓ No issues found!
The tool detects the following formatting patterns in source functions:
fmt.Errorf(...)used in return statementsfmt.Sprintf(...)+errors.New(...)combinations- Other error formatting patterns
Important: The tool only checks functions that provide errors to CheckDeletedDiag calls within ReadContext methods. Errors handled via diag.FromErr or diag.Errorf before reaching CheckDeletedDiag are ignored.
The tool uses Go's AST parser (go/parser and go/ast) for accurate function definition extraction:
- Advantages: Handles complex Go syntax correctly (nested functions, string literals, etc.)
- Fallback: Automatically falls back to regex-based extraction if AST parser is unavailable
- Performance: Compiled Go binary provides fast parsing
- Parallel Processing: Uses
ThreadPoolExecutorfor concurrent file processing - File Caching: Caches file contents to avoid redundant I/O operations
- Optimized Lookups: Efficient function lookup algorithms
- Result: Processes 3,340+ files in ~13.6 seconds
- Finds all
CheckDeletedDiagcalls inReadContextmethods - Traces the error variable back to its source function
- Verifies the error actually reaches
CheckDeletedDiag(not handled earlier) - Checks if the source function formats the error
- Reports issues with accurate line numbers
func GetV2AlarmRule(client *golangsdk.ServiceClient, alarmRuleId string) (interface{}, error) {
getResp, err := client.Request("GET", getPath, &getOpt)
if err != nil {
return nil, fmt.Errorf("error getting the alarm rule: %s", err) // ❌ Error formatted
}
// ...
}
func resourceAlarmRuleRead(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
// ...
alarmRule, err := GetV2AlarmRule(client, d.Id())
if err != nil {
return common.CheckDeletedDiag(d, err, "alarm rule") // Error from GetV2AlarmRule is formatted
}
// ...
}The above code will be detected as problematic because the GetV2AlarmRule function uses fmt.Errorf to format the error before it's passed to CheckDeletedDiag.
func GetV2AlarmRule(client *golangsdk.ServiceClient, alarmRuleId string) (interface{}, error) {
getResp, err := client.Request("GET", getPath, &getOpt)
if err != nil {
return nil, err // ✅ Return the original error directly without formatting
}
// ...
}func bindAclPolicyToApis(client *golangsdk.ServiceClient, policyId string, apiIds []string) error {
// ...
if err != nil {
return fmt.Errorf("error binding ACL policy: %s", err) // This won't be detected
}
// ...
}
func resourceAclPolicyAssociateCreate(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
// ...
err := bindAclPolicyToApis(client, policyId, apiIds)
if err != nil {
return diag.FromErr(err) // Error is handled here, not passed to CheckDeletedDiag
}
// ...
}The above code won't be detected because the error is handled via diag.FromErr before it could reach CheckDeletedDiag.
To add a new code quality rule:
- Create a new rule file in the
rules/cq_rules/directory (e.g.,rule_002.py) - Inherit the
BaseRuleclass and implement thecheck()method - Register the new rule in
check_error_format.py
Example:
from rules.base_rule import BaseRule, Issue
from pathlib import Path
from typing import List
class Rule002(BaseRule):
def __init__(self, show_progress: bool = False):
super().__init__(
rule_id="CQ.002",
rule_name="Rule Name",
description="Rule Description"
)
self.show_progress = show_progress
def check(self, root_dir: Path) -> List[Issue]:
# Implement check logic
# Use self.add_issue() to add issues
return self.get_issues()Then register it in check_error_format.py:
rules = [
Rule001(show_progress=show_progress),
Rule002(show_progress=show_progress), # Add new rule
]- Python: 3.10+ (uses only Python standard library)
- Go: 1.19+ (optional, for building Go AST parser)
The tool uses only Python standard library modules:
argparse- Command-line argument parsingconcurrent.futures- Parallel processingpathlib- Path handlingsubprocess- Calling Go AST parserjson- Parsing AST parser outputre- Regular expressions (fallback mode)
See LICENSE file.