Debug

Viewing a Go Program’s Command Line with /debug/pprof/cmdline

Learn how Go’s net/http/pprof cmdline endpoint exposes process argv, how to inspect NUL-separated output, troubleshoot access, and protect sensitive deployment details.

The /debug/pprof/cmdline endpoint reports the command-line arguments used to start the currently running Go process. It is a small but useful deployment-context check: before collecting CPU, heap, or goroutine data, you can confirm which executable and startup options are actually active.

This endpoint reports startup arguments, not a complete configuration dump. It does not directly show environment variables, the contents of configuration files, HTTP request parameters, or profiling data.

What the cmdline endpoint is for

In operating-system terminology, argv is the ordered argument vector supplied to a process when it starts. The cmdline handler returns that vector for the Go process serving the request.

This can answer questions such as:

  • Which executable or program name started this process?
  • Was the intended configuration file passed as an argument?
  • Is the service using the expected listen address?
  • Was a feature switch or operating mode enabled?
  • Did the inspected replica receive the startup arguments expected by the deployment?

The result is evidence about process startup. It is not necessarily evidence about the current effective configuration. A service may later reload a file, receive remote settings, or change an in-memory value without changing its original argv.

What it does not report

Configuration sourceVisible through cmdlineExampleDebugging implication
Startup argumentUsually yes--config=/etc/service/config.yamlStartup flags and their values can be verified directly.
Environment variableNoSERVICE_MODE=productionInspect the process environment or application status separately.
Configuration fileOnly its argument or path, if supplied/etc/service/config.yamlThe endpoint does not reveal the file contents or which values won precedence.
Built-in defaultNoA default timeout compiled into the programA missing flag does not mean the setting is absent; a default may be active.
Runtime reload or remote configurationNoA setting delivered by a control planeUse application status, logs, or configuration-specific diagnostics.

Where the endpoint comes from

net/http/pprof is a Go standard-library package that exposes HTTP debugging and profiling handlers. The usual path for this handler is /debug/pprof/cmdline.

A blank import loads the package for its initialization side effects:

import _ "net/http/pprof"

That import registers the pprof handlers on Go’s http.DefaultServeMux, also called the default ServeMux. A server that passes nil as its handler to http.ListenAndServe uses this default mux.

go func() {
    _ = http.ListenAndServe("127.0.0.1:6060", nil)
}()

In this example, pprof is available on a loopback-only diagnostics listener. An operator on the same host can query port 6060, while the public application listener can remain separate.

Default mux versus custom mux

A custom ServeMux is an application-created HTTP multiplexer, commonly made with http.NewServeMux(). Registering pprof on the default mux does not automatically add those handlers to a custom mux.

mux := http.NewServeMux()
// Register the desired pprof handlers explicitly, or run a separate
// diagnostics server with http.DefaultServeMux.

If the application serves only mux, a blank import by itself may not make /debug/pprof/cmdline available on that server. The application must explicitly wire the desired pprof handlers, or expose http.DefaultServeMux through a separate diagnostics server. The exact registration approach depends on the handlers and routing policy the application chooses.

For an overview of the available handlers, see the pprof index.

Response format: an argv vector separated by NUL bytes

The response represents arguments in order, with a NUL byte between adjacent arguments. A NUL byte is the zero byte, written as \x00 in many tools. The response is commonly served as text/plain, but it is not line-oriented text.

For example, a process might have this argument vector:

argv[0] = /usr/local/bin/orders
argv[1] = --config
argv[2] = /etc/orders/config.yaml
argv[3] = --listen
argv[4] = 127.0.0.1:8080
argv[5] = --display-name
argv[6] = nightly orders service

The raw response is conceptually:

/usr/local/bin/orders\x00--config\x00/etc/orders/config.yaml\x00--listen\x00127.0.0.1:8080\x00--display-name\x00nightly orders service

The spaces in nightly orders service do not create additional arguments. That value remains one argv element because argument boundaries are marked by NUL bytes, not spaces.

Shell quoting used when the process was launched is not preserved. For example, a launcher command containing --display-name "nightly orders service" supplies the post-shell value nightly orders service. The endpoint reports that value, not the quote characters or the original shell syntax.

Browsers and ordinary terminal output may show NUL delimiters as odd characters, suppress them, or make the result look like one run-on string. Render the bytes deliberately when inspecting the response.

Accessing and inspecting the endpoint

Fetch the raw response locally

curl --silent http://127.0.0.1:6060/debug/pprof/cmdline

If pprof is attached to the application listener instead, replace the address and port with that listener. If it is on a separate diagnostics port, query that port directly:

curl --silent http://127.0.0.1:6060/debug/pprof/cmdline

When a reverse proxy exposes a protected internal route, use the proxy’s approved internal hostname and path rather than assuming that the public application address serves pprof.

Render one argument per line

curl --silent http://127.0.0.1:6060/debug/pprof/cmdline | tr '\0' '\n'

This changes only the display representation. It replaces each NUL separator with a newline so that each argv element is easier to inspect. Do not split the response on spaces; doing so would destroy the true boundaries of values that contain spaces.

Inspect the raw bytes

curl --silent http://127.0.0.1:6060/debug/pprof/cmdline | od -An -t x1c

The byte-oriented output lets you verify that separators are zero bytes. It is useful when a terminal renders the response confusingly or when an argument contains non-printing characters.

Preserve boundaries in shell processing

Tools that understand NUL-delimited input can preserve argument boundaries. For example, a NUL-aware command can consume the response with an option such as -0 or --null, when that option is supported. Avoid command substitutions that rely on whitespace splitting when exact argv boundaries matter.

Interpreting common output

The first item is conventionally the executable path or program name, known as argv[0]. It may be an absolute path, a relative path, or simply a program name, depending on how the process was launched.

Remaining items are positional arguments and flags. A flag may occupy one argument with its value in the same element, such as --config=/etc/orders/config.yaml, or two elements, such as --config followed by /etc/orders/config.yaml. The endpoint reports whichever form the program received.

argv[0] = /usr/local/bin/orders
argv[1] = --config=/etc/orders/config.yaml
argv[2] = --listen
argv[3] = 127.0.0.1:8080
argv[4] = --display-name
argv[5] = nightly orders service

In this example, argv[5] is one argument despite containing two spaces. This distinction matters when verifying a deployment command, wrapper script, or feature flag.

Using cmdline during deployment debugging

Suppose an orchestration configuration is expected to start a service with --config=/etc/orders/prod.yaml and --mode=active. Render the endpoint into separate lines and check whether those exact argument values appear.

If they do appear, startup argument delivery is probably not the source of the mismatch. Continue by checking file contents, environment variables, defaults, precedence rules, and runtime reload behavior.

If they do not appear, verify the queried instance and listener. A load balancer may route you to another replica. A container entrypoint or supervisor may also alter the command before the Go binary starts. The Go process’s argv can differ from the command shown in orchestration metadata or from the arguments of a wrapper process.

Supervisor and container boundaries

The endpoint describes only the Go process that serves the request. It does not necessarily describe:

  • A shell or wrapper that launched the Go binary.
  • A supervisor’s own process arguments.
  • A container runtime’s complete entrypoint metadata.
  • Arguments belonging to a sidecar or another process in the same workload.

Compare the returned argv with the runtime process list, container metadata, routing information, and instance identity before concluding that the deployment is incorrect.

Security and operational exposure

Command-line arguments are often visible to operators and, on some systems, to other users with process-inspection privileges. They may contain database URLs, access tokens, passwords, tenant identifiers, internal file paths, or deployment details.

Public exposure is risky even though this endpoint does not return CPU samples, heap samples, or goroutine profiles. Startup arguments can disclose credentials and useful information about internal infrastructure.

Prefer these controls:

  • Bind a diagnostics listener to 127.0.0.1 when only local access is required.
  • Place pprof on a private diagnostics network or dedicated diagnostics port.
  • Require authentication and authorization through a protected administrative proxy.
  • Restrict source networks with firewall or reverse-proxy policy.
  • Avoid putting secrets in command-line flags.
  • Use an appropriate secret-delivery mechanism, such as a protected file, credential store, or secret service, while considering the permissions and lifecycle of that mechanism.
location /debug/pprof/ {
    allow 10.0.0.0/8;
    deny all;
    proxy_pass http://127.0.0.1:6060;
}

This reverse-proxy example illustrates network restriction, not a complete authentication policy. Combine allowlists with authentication, TLS, logging, and least-privilege access where appropriate.

Relationship to other pprof diagnostics

EndpointPrimary outputTypical debugging questionSensitive information considerations
/debug/pprof/Index and navigation to diagnostic handlersWhich pprof handlers are available?Reveals that diagnostics are enabled and may list useful endpoints.
/debug/pprof/cmdlineProcess argvHow was this Go process started?May expose secrets, paths, flags, and deployment details.
/debug/pprof/profileCPU profile over a sampling intervalWhere is the process spending CPU time?Profile data can reveal implementation and workload details.
/debug/pprof/heapHeap and allocation profile dataWhat objects and allocation sites use memory?May expose application behavior and data-related details.
/debug/pprof/goroutineGoroutine profiles or stack informationWhich goroutines are blocked, running, or stuck?Stacks can reveal internal paths, services, and request context.
/debug/pprof/traceGo execution traceHow did scheduling and execution behave over time?Trace data can reveal timing, workload, and internal activity.

Use cmdline as an initial deployment-context verification step. Once you know that you are querying the intended process with the intended startup mode, choose the profile or trace that answers the performance question.

Limitations and platform considerations

  • The endpoint reflects how the process was started, not necessarily its current effective configuration.
  • Argument availability and exact representation depend on operating-system process semantics and runtime behavior.
  • An empty or minimal result does not prove that the service has no configuration. Settings may come from environment variables, files, defaults, or remote services.
  • The endpoint reports the Go process serving the request, which may differ from a supervisor, wrapper, container entrypoint, or sidecar.
  • It is not a substitute for an authenticated configuration or status endpoint when current settings must be verified.

Troubleshooting

HTTP 404 for /debug/pprof/cmdline

  • Check that net/http/pprof was imported or that the handlers were registered explicitly.
  • Confirm which listener serves pprof. The application port may not be the diagnostics port.
  • If the application uses a custom mux, verify that the cmdline handler was wired into that mux, or query a separate server using http.DefaultServeMux.
  • Check reverse-proxy routing and path restrictions.

The output is a run-on string or contains odd characters

The response uses NUL separators, which many viewers do not render as line breaks. Use tr '\0' '\n' for readable lines or od to inspect the bytes. Do not split on spaces.

An expected setting is missing

The setting may come from an environment variable, configuration file, built-in default, or remote configuration. It may also have changed after startup. Inspect the relevant source and application status, and verify that the queried process, host, replica, and listener are the intended ones.

The endpoint reveals a secret

Rotate the exposed credential, restrict or disable external pprof access, and move secret delivery away from command-line arguments. Treat command-line values as potentially observable operational data.

The executable or flags differ from the deployment command

A wrapper, supervisor, or container entrypoint may have transformed the command. Compare the Go process argv with runtime process information and orchestration metadata, then confirm that routing did not send the request to a different instance.

Summary

  • /debug/pprof/cmdline returns the running Go process’s ordered startup arguments, or argv.
  • Arguments are separated by NUL bytes, not newlines or spaces.
  • Use curl, tr, and od to fetch, render, and verify the response.
  • A blank import commonly registers pprof on http.DefaultServeMux; custom muxes require explicit wiring.
  • The endpoint confirms startup context but does not reveal all current process configuration.
  • Protect pprof because command-line arguments can contain sensitive credentials and deployment information.

After checking startup context, continue with the pprof handlers appropriate to the incident. Other runtime variables may be available through /debug/vars/, while an application’s pprof navigation page can be viewed at the default pprof view.