Flags code that flattens unknown caught values into generic strings like error.message or String(error).
- Family:
defensive - Severity:
strong - Scope:
file - Requires:
file.ast
The rule looks for conditional expressions like:
error instanceof Error ? error.message : String(error)err instanceof Error ? err.message : String(err)- equivalent forms assigned into
message/errorproperties or returned directly
This pattern is common in generated wrapper code that wants a quick printable error value. It is sometimes reasonable, but repeated use often flattens richer failure objects into plain strings and makes downstream diagnostics more generic.
To avoid obvious vendored noise, the rule skips very large bundled/generated files over 5000 logical lines.
catch (error) {
return { success: false, error: error instanceof Error ? error.message : String(error) };
}
setError(err instanceof Error ? err.message : String(err));
const message = error instanceof Error ? error.message : String(error);catch (error) {
throw error;
}
catch (error) {
logger.error({ error });
return { success: false, error };
}Prefer preserving structured error information over collapsing everything into a string.
Better options:
- propagate the original error object
- log structured fields and keep the original error attached
- map errors into typed domain variants instead of generic message strings
- stringify only at the final UI or logging boundary
catch (error) {
logger.error({ error });
return { success: false, error };
}If the UI really needs a display string, derive it at the edge of the system rather than erasing the richer error earlier in the flow.
Each unknown-error stringification site adds 2 points.
The file total is capped at 8.
Small pinned rule benchmark (manifest):
- Signal rank: #4 of 9
- Signal score: 0.70 / 1.00
- Best separating metric: findings / file (0.80)
- Hit rate: 4/6 AI repos vs 1/5 mature OSS repos
- Full results: rule signal report