Skip to content

pre-start scripts fails when JAVA_OPTS contains special characters #1259

@stokpop

Description

@stokpop

When JAVA_OPTS is defined in a CF manifest using a YAML block scalar (>), CF may deliver the value with literal newlines, or the value may contain pipe characters (|) as part of javaagent options:

env:
  JAVA_OPTS: >
    -javaagent:$HOME/BOOT-INF/lib/jfr-exporter.jar=enableExecutorMBeans|disableMyFeature
    -XX:+UseZGC
    -XX:+AlwaysPreTouch
    -XX:-ZUncommit
    -XX:MaxDirectMemorySize=256m

The profile.d/00_java_opts.sh script uses sed to substitute $JAVA_OPTS, $HOME and $DEPS_DIR into each .opts file. The sed delimiter is |, and the replacement string is not sanitised, so the command fails when the value contains | or newlines:

[APP/PROC/WEB/0] OUT Invoking pre-start scripts.
[APP/PROC/WEB/0] ERR sed: -e expression #1, char 257: unterminated `s` command
[APP/PROC/WEB/0] ERR sed: -e expression #1, char 257: unterminated `s` command
[APP/PROC/WEB/0] ERR sed: -e expression #1, char 257: unterminated `s` command
[APP/PROC/WEB/0] ERR sed: -e expression #1, char 257: unterminated `s` command

The error repeats once per .opts file. Because the script has no set -e, execution continues — but all opts content is dropped and the JVM starts with an empty JAVA_OPTS: no memory limits, no agents.

Additionally, & and \ in JAVA_OPTS are interpreted as sed replacement metacharacters, causing silent data corruption instead of a visible error.

The ERR lines are only visible in CF application logs; there is no staging failure or app crash that directly points to this cause.

Impact

All JVM flags are silently dropped at startup:

  • Buildpack-calculated memory settings (-Xmx, -Xss, -XX:MaxMetaspaceSize) absent → OOM / GC thrashing
  • Java agents not attached → no APM/tracing instrumentation
  • -Djava.security.properties missingCloudFoundryContainerProvider not registered → CF system certificates not loaded into JVM truststore → TLS handshake failures: (certificate_unknown) No trusted certificate found

The last point is tricky to diagnose: the connection between the sed error lines at startup and TLS failures later at runtime is not obvious.

Suggestions

  • Avoid sed for variable substitution in the assembly script; use bash parameter expansion instead, which has no special-character restrictions
  • Normalize JAVA_OPTS to a single line before substitution to handle YAML block scalar newlines
  • Consider adding set -e to the script so that any failure causes a hard stop rather than continuing with an empty or corrupt JAVA_OPTS

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions