{"record":{"id":"4b1708147e6e6422","repo":"rectorphp/rector","slug":"s-rule-is-deprecated-as-it-can-cause-bc-breaks","errorCode":null,"errorMessage":"\"%s\" rule is deprecated, as it can cause BC breaks. The thrown JsonException has to be handled manually on every call site","messagePattern":"\"(.+?)\" rule is deprecated, as it can cause BC breaks\\. The thrown JsonException has to be handled manually on every call site","errorType":"exception","errorClass":"ShouldNotHappenException","httpStatus":null,"severity":"error","filePath":"rules/Php73/Rector/FuncCall/JsonThrowOnErrorRector.php","lineNumber":41,"sourceCode":"json_encode($content);\njson_decode($json);\nCODE_SAMPLE\n, <<<'CODE_SAMPLE'\njson_encode($content, JSON_THROW_ON_ERROR);\njson_decode($json, null, 512, JSON_THROW_ON_ERROR);\nCODE_SAMPLE\n)]);\n    }\n    /**\n     * @return array<class-string<Node>>\n     */\n    public function getNodeTypes(): array\n    {\n        return NodeGroup::STMTS_AWARE;\n    }\n    public function refactor(Node $node): ?Node\n    {\n        throw new ShouldNotHappenException(sprintf('\"%s\" rule is deprecated, as it can cause BC breaks. The thrown JsonException has to be handled manually on every call site', self::class));\n    }\n    public function provideMinPhpVersion(): int\n    {\n        return PhpVersionFeature::JSON_EXCEPTION;\n    }\n}\n","sourceCodeStart":23,"sourceCodeEnd":48,"githubUrl":"https://github.com/rectorphp/rector/blob/408fcb0ff1833e3d26cbc9b04c23a77565814a16/rules/Php73/Rector/FuncCall/JsonThrowOnErrorRector.php#L23-L48","documentation":"Rector\\Php73\\Rector\\FuncCall\\JsonThrowOnErrorRector is deprecated: instead of removing the class, its refactor() now unconditionally throws Rector\\Exception\\ShouldNotHappenException with the deprecation reason. The rule used to add JSON_THROW_ON_ERROR to json_encode()/json_decode() calls, but the resulting JsonException is not caught by code written for the old null/false error style, which is a behavioral (BC) break. Because getNodeTypes() returns NodeGroup::STMTS_AWARE, the exception fires on the first analyzed file containing statements.","triggerScenarios":"The rule is still listed in rector.php (via ->withRules([JsonThrowOnErrorRector::class]) or ->withConfiguredRule(...)) and `vendor/bin/rector` visits any statement-aware node; refactor() is called on the first match and throws immediately.","commonSituations":"Upgrading rector/rector to a release where this rule was gutted while keeping an old rector.php; CI failing on the first parsed file after `composer update`; configs shared across projects that still reference the rule name.","solutions":["Remove JsonThrowOnErrorRector from the ->withRules()/->withConfiguredRule() list in rector.php; the rule performs no migration anymore.","If you want throwing JSON calls, edit each call site manually: pass JSON_THROW_ON_ERROR and wrap the call in a try/catch (JsonException) that fits the surrounding error handling.","If automation is required for a controlled codebase, write a small project-scoped custom rule that adds the flag only where the call site was reviewed.","As a temporary stopgap only, pin the last rector/rector version that ships the working rule; plan its removal before the next upgrade."],"exampleFix":"// before (rector.php)\nreturn RectorConfig::configure()\n    ->withRules([JsonThrowOnErrorRector::class]);\n\n// after (rector.php) - rule removed, migrate call sites by hand\nreturn RectorConfig::configure()\n    ->withPhp73();\n\n// before (src/Api.php)            // after (src/Api.php)\n$value = json_decode($raw);        try {\n                                        $value = json_decode($raw, true, 512, JSON_THROW_ON_ERROR);\n                                    } catch (JsonException $e) {\n                                        throw new MalformedPayloadException($raw, $e);\n                                    }","handlingStrategy":"validation","validationCode":"use Rector\\Php73\\Rector\\FuncCall\\JsonThrowOnErrorRector;\n\n$rules = [/* your withRules() list */ JsonThrowOnErrorRector::class];\n$deprecated = [JsonThrowOnErrorRector::class];\n$hit = array_intersect($rules, $deprecated);\nif ($hit !== []) {\n    throw new InvalidArgumentException('Remove deprecated rector rules before running: ' . implode(', ', $hit));\n}","typeGuard":null,"tryCatchPattern":"try {\n    exit($rectorApplication->run());\n} catch (\\Rector\\Exception\\ShouldNotHappenException $e) {\n    if (str_contains($e->getMessage(), 'rule is deprecated')) {\n        // config debt, not a code problem: strip the named rule from rector.php and re-run\n        fwrite(STDERR, 'Config fix needed: ' . $e->getMessage() . PHP_EOL);\n        exit(1);\n    }\n    throw $e;\n}","preventionTips":["After every rector/rector upgrade, grep rector.php for rule names listed in the release notes' removed-rules section and delete them.","Prefer version sets (->withPhp73()) over long explicit withRules() lists; sets are maintained by rector and drop gutted rules.","Run vendor/bin/rector --dry-run on a small fixture path in CI before processing the whole codebase.","Treat a ShouldNotHappenException containing 'rule is deprecated' as a config problem - never patch the analyzed code around it."],"tags":["rector","php","json","deprecated-rule","bc-break","php73"],"backgroundTag":"deprecated-api-invoked","analyzedSha":"408fcb0ff1833e3d26cbc9b04c23a77565814a16","analyzedAt":"2026-08-21T05:11:02.643Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}