[ 
https://issues.apache.org/jira/browse/GROOVY-12732?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Scott Murphy Heiberg updated GROOVY-12732:
------------------------------------------
    Description: 
When a script throws, the {{groovy}} command logs its message with the 
placeholder unfilled, then prints the exception's stack trace twice: first 
unsanitized, through the logger, then sanitized, by {{printStackTrace()}}.

Throws.groovy:
{code:groovy}
throw new IllegalStateException('boom')
{code}

Groovy 6.0.0 on JDK 25:
{noformat}
$ groovy Throws.groovy
Nov 07, 2026 10:58:15 PM groovy.ui.GroovyMain run
SEVERE: Caught: {0}
java.lang.IllegalStateException: boom
        at Throws.run(Throws.groovy:1)
        at 
groovy.lang.GroovyShell.runScriptOrMainOrTestOrRunnable(GroovyShell.java:322)
        at groovy.lang.GroovyShell.run(GroovyShell.java:468)
        at groovy.lang.GroovyShell.run(GroovyShell.java:457)
        at groovy.ui.GroovyMain.processOnce(GroovyMain.java:851)
        at groovy.ui.GroovyMain.run(GroovyMain.java:450)
        at groovy.ui.GroovyMain$GroovyCommand.process(GroovyMain.java:355)
        at groovy.ui.GroovyMain.processArgs(GroovyMain.java:168)
        at groovy.ui.GroovyMain.main(GroovyMain.java:127)
        at 
java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
        at java.base/java.lang.reflect.Method.invoke(Method.java:565)
        at 
org.codehaus.groovy.tools.GroovyStarter.rootLoader(GroovyStarter.java:150)
        at org.codehaus.groovy.tools.GroovyStarter.main(GroovyStarter.java:52)

java.lang.IllegalStateException: boom
        at Throws.run(Throws.groovy:1)
{noformat}

The 6.0.1-SNAPSHOT and master behave the same. Before GROOVY-11886 the command 
printed {{Caught: java.lang.IllegalStateException: boom}} and then the 
sanitized trace once.

Cause: GROOVY-11886 replaced {{System.err.println("Caught: " + e)}} in 
{{GroovyMain.run()}} with
{code:java}
LOGGER.log(ERROR, "Caught: {0}", e);
{code}
Because {{e}} is a {{Throwable}}, Java selects {{System.Logger.log(Level, 
String, Throwable)}} rather than {{log(Level, String, Object...)}}. The message 
is not formatted, and the throwable is logged with its full stack trace before 
{{StackTraceUtils.deepSanitize}} runs, so that copy ignores the {{-d}} setting.

The same cause affects one other call. When the {{groovy.ast=xml}} AST dump 
cannot be written, {{XStreamUtils.serialize}} logs
{code:java}
LOGGER.log(WARNING, "Couldn''t write to " + name + ".xml", e);
{code}
GROOVY-11886 doubled the apostrophe for {{MessageFormat}}, but a message logged 
with a throwable is not formatted, so the warning shows both apostrophes. 
Groovy 6.0.0, with Hello.groovy in a directory the user cannot write to:
{noformat}
$ JAVA_OPTS=-Dgroovy.ast=xml groovy Hello.groovy
Nov 08, 2026 1:34:38 AM org.codehaus.groovy.control.XStreamUtils serialize
WARNING: Couldn''t write to <dir>/Hello.groovy.xml
java.io.FileNotFoundException: <dir>/Hello.groovy.xml (Permission denied)
        at java.base/java.io.FileOutputStream.open0(Native Method)
{noformat}
Every other logging call that has a placeholder or a doubled apostrophe passes 
arguments that are not throwables, so it is formatted as intended.

The {{GroovyMain}} line was noticed, as a side note, in the description of 
GROOVY-12683.

Fix: in {{GroovyMain}}, log the text only, {{LOGGER.log(ERROR, "Caught: " + 
e)}}, and keep the single sanitized {{printStackTrace()}}. In {{XStreamUtils}}, 
write a single apostrophe. Pull request: 
https://github.com/apache/groovy/pull/3267, with a test for each in 
{{GroovyMainTest}} and {{XStreamUtilsTest}}.

  was:
When a script throws, the {{groovy}} command logs its message with the 
placeholder unfilled, then prints the exception's stack trace twice: first 
unsanitized, through the logger, then sanitized, by {{printStackTrace()}}.

Throws.groovy:
{code:groovy}
throw new IllegalStateException('boom')
{code}

Groovy 6.0.0 on JDK 25:
{noformat}
$ groovy Throws.groovy
Nov 07, 2026 10:58:15 PM groovy.ui.GroovyMain run
SEVERE: Caught: {0}
java.lang.IllegalStateException: boom
        at Throws.run(Throws.groovy:1)
        at 
groovy.lang.GroovyShell.runScriptOrMainOrTestOrRunnable(GroovyShell.java:322)
        at groovy.lang.GroovyShell.run(GroovyShell.java:468)
        at groovy.lang.GroovyShell.run(GroovyShell.java:457)
        at groovy.ui.GroovyMain.processOnce(GroovyMain.java:851)
        at groovy.ui.GroovyMain.run(GroovyMain.java:450)
        at groovy.ui.GroovyMain$GroovyCommand.process(GroovyMain.java:355)
        at groovy.ui.GroovyMain.processArgs(GroovyMain.java:168)
        at groovy.ui.GroovyMain.main(GroovyMain.java:127)
        at 
java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
        at java.base/java.lang.reflect.Method.invoke(Method.java:565)
        at 
org.codehaus.groovy.tools.GroovyStarter.rootLoader(GroovyStarter.java:150)
        at org.codehaus.groovy.tools.GroovyStarter.main(GroovyStarter.java:52)

java.lang.IllegalStateException: boom
        at Throws.run(Throws.groovy:1)
{noformat}

The 6.0.1-SNAPSHOT and master behave the same. Before GROOVY-11886 the command 
printed {{Caught: java.lang.IllegalStateException: boom}} and then the 
sanitized trace once.

Cause: GROOVY-11886 replaced {{System.err.println("Caught: " + e)}} in 
{{GroovyMain.run()}} with
{code:java}
LOGGER.log(ERROR, "Caught: {0}", e);
{code}
Because {{e}} is a {{Throwable}}, Java selects {{System.Logger.log(Level, 
String, Throwable)}} rather than {{log(Level, String, Object...)}}. The message 
is not formatted, and the throwable is logged with its full stack trace before 
{{StackTraceUtils.deepSanitize}} runs, so that copy ignores the {{-d}} setting. 
The same cause affects one other call. When the {{groovy.ast=xml}} AST dump 
cannot be written, {{XStreamUtils.serialize}} logs
{code:java}
LOGGER.log(WARNING, "Couldn''t write to " + name + ".xml", e);
{code}
GROOVY-11886 doubled the apostrophe for {{MessageFormat}}, but a message logged 
with a throwable is not formatted, so the warning shows both apostrophes. 
Groovy 6.0.0, with Hello.groovy in a directory the user cannot write to:
{noformat}
$ JAVA_OPTS=-Dgroovy.ast=xml groovy Hello.groovy
Nov 08, 2026 1:34:38 AM org.codehaus.groovy.control.XStreamUtils serialize
WARNING: Couldn''t write to <dir>/Hello.groovy.xml
java.io.FileNotFoundException: <dir>/Hello.groovy.xml (Permission denied)
        at java.base/java.io.FileOutputStream.open0(Native Method)
{noformat}
Every other logging call that has a placeholder or a doubled apostrophe passes 
arguments that are not throwables, so it is formatted as intended.

The line was noticed, as a side note, in the description of GROOVY-12683.

Fix: in {{GroovyMain}}, log the text only, {{LOGGER.log(ERROR, "Caught: " + 
e)}}, and keep the single sanitized {{printStackTrace()}}. In {{XStreamUtils}}, 
write a single apostrophe. Pull request: 
https://github.com/apache/groovy/pull/3267, with a test for each in 
{{GroovyMainTest}} and {{XStreamUtilsTest}}.


> groovy command logs "Caught: {0}" and prints the stack trace twice; the AST 
> dump warning reads "Couldn''t write"
> ----------------------------------------------------------------------------------------------------------------
>
>                 Key: GROOVY-12732
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12732
>             Project: Groovy
>          Issue Type: Bug
>          Components: command line processing
>    Affects Versions: 6.0.0
>            Reporter: Scott Murphy Heiberg
>            Priority: Major
>
> When a script throws, the {{groovy}} command logs its message with the 
> placeholder unfilled, then prints the exception's stack trace twice: first 
> unsanitized, through the logger, then sanitized, by {{printStackTrace()}}.
> Throws.groovy:
> {code:groovy}
> throw new IllegalStateException('boom')
> {code}
> Groovy 6.0.0 on JDK 25:
> {noformat}
> $ groovy Throws.groovy
> Nov 07, 2026 10:58:15 PM groovy.ui.GroovyMain run
> SEVERE: Caught: {0}
> java.lang.IllegalStateException: boom
>       at Throws.run(Throws.groovy:1)
>       at 
> groovy.lang.GroovyShell.runScriptOrMainOrTestOrRunnable(GroovyShell.java:322)
>       at groovy.lang.GroovyShell.run(GroovyShell.java:468)
>       at groovy.lang.GroovyShell.run(GroovyShell.java:457)
>       at groovy.ui.GroovyMain.processOnce(GroovyMain.java:851)
>       at groovy.ui.GroovyMain.run(GroovyMain.java:450)
>       at groovy.ui.GroovyMain$GroovyCommand.process(GroovyMain.java:355)
>       at groovy.ui.GroovyMain.processArgs(GroovyMain.java:168)
>       at groovy.ui.GroovyMain.main(GroovyMain.java:127)
>       at 
> java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
>       at java.base/java.lang.reflect.Method.invoke(Method.java:565)
>       at 
> org.codehaus.groovy.tools.GroovyStarter.rootLoader(GroovyStarter.java:150)
>       at org.codehaus.groovy.tools.GroovyStarter.main(GroovyStarter.java:52)
> java.lang.IllegalStateException: boom
>       at Throws.run(Throws.groovy:1)
> {noformat}
> The 6.0.1-SNAPSHOT and master behave the same. Before GROOVY-11886 the 
> command printed {{Caught: java.lang.IllegalStateException: boom}} and then 
> the sanitized trace once.
> Cause: GROOVY-11886 replaced {{System.err.println("Caught: " + e)}} in 
> {{GroovyMain.run()}} with
> {code:java}
> LOGGER.log(ERROR, "Caught: {0}", e);
> {code}
> Because {{e}} is a {{Throwable}}, Java selects {{System.Logger.log(Level, 
> String, Throwable)}} rather than {{log(Level, String, Object...)}}. The 
> message is not formatted, and the throwable is logged with its full stack 
> trace before {{StackTraceUtils.deepSanitize}} runs, so that copy ignores the 
> {{-d}} setting.
> The same cause affects one other call. When the {{groovy.ast=xml}} AST dump 
> cannot be written, {{XStreamUtils.serialize}} logs
> {code:java}
> LOGGER.log(WARNING, "Couldn''t write to " + name + ".xml", e);
> {code}
> GROOVY-11886 doubled the apostrophe for {{MessageFormat}}, but a message 
> logged with a throwable is not formatted, so the warning shows both 
> apostrophes. Groovy 6.0.0, with Hello.groovy in a directory the user cannot 
> write to:
> {noformat}
> $ JAVA_OPTS=-Dgroovy.ast=xml groovy Hello.groovy
> Nov 08, 2026 1:34:38 AM org.codehaus.groovy.control.XStreamUtils serialize
> WARNING: Couldn''t write to <dir>/Hello.groovy.xml
> java.io.FileNotFoundException: <dir>/Hello.groovy.xml (Permission denied)
>       at java.base/java.io.FileOutputStream.open0(Native Method)
> {noformat}
> Every other logging call that has a placeholder or a doubled apostrophe 
> passes arguments that are not throwables, so it is formatted as intended.
> The {{GroovyMain}} line was noticed, as a side note, in the description of 
> GROOVY-12683.
> Fix: in {{GroovyMain}}, log the text only, {{LOGGER.log(ERROR, "Caught: " + 
> e)}}, and keep the single sanitized {{printStackTrace()}}. In 
> {{XStreamUtils}}, write a single apostrophe. Pull request: 
> https://github.com/apache/groovy/pull/3267, with a test for each in 
> {{GroovyMainTest}} and {{XStreamUtilsTest}}.



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)
  • [jira] [Updated] (GROOVY-127... Scott Murphy Heiberg (Jira) via notifications

Reply via email to