Skip to content

php-cli (v1.13.0): $argv[0] is "frankenphp" and the script path is shifted to $argv[1] — breaks Symfony Console #2690

Closed

Description

@areqq

What happened?

Since v1.13.0, frankenphp php-cli script.php args... exposes the binary name as $argv[0] and shifts the script path to $argv[1] ($argc grows by one). Native php and FrankenPHP ≤ 1.12.7 expose the script path as $argv[0], as documented for the CLI SAPI.

Minimal reproduction (same PHP 8.5.11, only FrankenPHP differs):

<?php printf("PHP %s SAPI=%s argc=%d argv=%s\n", PHP_VERSION, PHP_SAPI, $argc, json_encode($argv));
# dunglas/frankenphp:1.12.7-php8.5
php                /t/argv.php foo bar  → PHP 8.5.11 SAPI=cli argc=3 argv=["/t/argv.php","foo","bar"]
frankenphp php-cli /t/argv.php foo bar  → PHP 8.5.11 SAPI=cli argc=3 argv=["/t/argv.php","foo","bar"]

# dunglas/frankenphp:1.13.0-php8.5
php                /t/argv.php foo bar  → PHP 8.5.11 SAPI=cli argc=3 argv=["/t/argv.php","foo","bar"]
frankenphp php-cli /t/argv.php foo bar  → PHP 8.5.11 SAPI=cli argc=4 argv=["frankenphp","/t/argv.php","foo","bar"]

$_SERVER['argv'] shows the same shift. SCRIPT_NAME, PHP_SELF and SCRIPT_FILENAME are correct in both versions. Passing -- does not help (-- then shows up inside $argv).

Impact: anything that treats $argv[0] as the script and $argv[1] as the first argument breaks. The most visible case is Symfony Console: ArgvInput drops argv[0] and takes the next element as the command name, so every command fails with

Command "/app/bin/console" is not defined.

This affects frankenphp php-cli bin/console doctrine:migrations:migrate, messenger:consume, messenger:stop-workers, etc. The HTTP server and worker mode are unaffected.

Likely cause: #1757 ("simply use the built-in php-cli"). caddy/php-cli.go now builds the argument vector as append([]string{os.Args[0]}, os.Args[2:]...) (the binary name is prepended so option parsing works like php -i) and passes it unchanged through frankenphp_execute_script_cli to do_php_cli(argc, argv). The real php binary shifts the vector after option parsing so that the script becomes $argv[0]; that shift does not happen on this code path, so user scripts see the raw vector including the binary name. The pre-1.13 emulation built the vector starting at the script path, which is why it was correct before.

Expected: frankenphp php-cli script.php a b gives $argv === ["script.php","a","b"], exactly like php script.php a b.

Build Type

Official Docker image (dunglas/frankenphp:1.13.0-php8.5); also reproduced with a custom build of v1.13.0.

Worker Mode

No — CLI only (php-cli), unrelated to worker mode.

Operating System

GNU/Linux (Debian-based official image; host: Linux x86_64, podman 5.8)

CPU Architecture

x86_64

PHP configuration

phpinfo() output

PHP 8.5.11 (bundled in the official image), default php.ini, no custom extensions needed to reproduce. The repro script above has no dependencies.

Relevant log output

Relevant log output
$ podman run --rm -v $PWD/argv.php:/t/argv.php:ro dunglas/frankenphp:1.13.0-php8.5 frankenphp version
FrankenPHP v1.13.0 PHP 8.5.11 Caddy v2.11.7 h1:yj0Y4fYZGPkSvibBJ1sTWE33xC0fxztVyXEW5iIdUT4=

$ podman run --rm -v $PWD/argv.php:/t/argv.php:ro dunglas/frankenphp:1.13.0-php8.5 frankenphp php-cli /t/argv.php foo bar
PHP 8.5.11 SAPI=cli argc=4 argv=["frankenphp","\/t\/argv.php","foo","bar"]

$ podman run --rm -v $PWD/argv.php:/t/argv.php:ro dunglas/frankenphp:1.12.7-php8.5 frankenphp php-cli /t/argv.php foo bar
PHP 8.5.11 SAPI=cli argc=3 argv=["\/t\/argv.php","foo","bar"]

# Symfony 7.4 app, same container, v1.13.0:
$ frankenphp php-cli /app/bin/console doctrine:migrations:migrate -n
  Command "/app/bin/console" is not defined.

Activity

  1. nickchomey commented on Oct 4, 2026

    @nickchomey

    I think this bit me today when using https://github.com/wp-cli/wp-cli

  2. famfop commented on Oct 6, 2026

    @famfop

    This breaks my image because I cannot run db-migrations that usually are triggered like frankenphp php-cli upgrade.php with the same errors as reported. I tested it like this:

    $ echo '<?php var_dump($_SERVER["argv"], $argv);' > /tmp/argv.php
    $ /frankenphp php-cli /tmp/argv.php --foo
    array(3) {
      [0]=>
      string(11) "/frankenphp"
      [1]=>
      string(13) "/tmp/argv.php"
      [2]=>
      string(5) "--foo"
    }
    

    I am looking forward to the PR getting merged (and thank you BTW)

  3. henderkes commented on Oct 6, 2026

    @henderkes
    Contributor

    Sorry for introducing the bug in the first place, our tests didn't cover argv placement 😢

  4. kevincobain2000 commented on Oct 6, 2026

    @kevincobain2000
    Contributor

    breaks composer too

    frankenphp.1.13.0 php-cli ~/.local/bin/composer dump-autoload --optimize --no-scripts
    
      Command "/home/<user>/.local/bin/composer" is not defined.
    
  5. added a commit that references this issue on Oct 7, 2026
  6. ramonmalcolm10 commented on Oct 7, 2026

    @ramonmalcolm10

    Same here. Adding a data point because it's not just Symfony apps: Composer breaks too, since it's a Symfony Console app as well.

    On a static 1.13.0 build (PHP 8.5), frankenphp php-cli /opt/homeport/composer.phar install --no-dev fails with:

    Command "/opt/homeport/composer.phar" is not defined.
    

    On 1.12.7 the same command works. Laravel's artisan goes through the same ArgvInput, so php-cli artisan migrate etc. hit it as well.

    This keeps us pinned to 1.12.7. That hurts a bit, because 1.13.0 also has the fix from #2612, for requests that hang when they arrive before the regular threads are ready. We see that hang on about a third of cold starts.

  7. added a commit that references this issue on Oct 10, 2026
    1406df0
  8. added a commit that references this issue on Oct 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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