Skip to content

Interpreter Test::Mojo startup loses application before Daemon server initialization #1644

Description

@fglock

Confirmed behavior and scope

On the interpreter backend, a minimal Test::Mojo request aborts while starting Mojo::Server::Daemon because its application accessor returns undef. The exact same program passes on standard Perl and the JVM backend when using the upstream default request timeout. It requires only a local loopback listener, not an external server or fork.

Candidate: d3f9ae5ac31b51810c0d3b83f302438e656a496a (PerlOnJava 5.44.1), PR #1628. Environment: macOS/Darwin arm64, Temurin OpenJDK 24.0.2+12, standard Perl 5.42.2. Distribution: Mojolicious 9.49 (pure Perl). Investigation date: 2026-10-05.

Complete reproducer code

Save this as repro.t:

use strict;
use warnings;
BEGIN { $ENV{MOJO_REACTOR} = 'Mojo::Reactor::Poll' }
use Mojolicious::Lite;
use Test::Mojo;
use Test::More;
my $t = Test::Mojo->new;
$t->get_ok('/nothing' => {Accept => 'image/png'})->status_is(404);
done_testing;

Do not add an artificially short inactivity timeout. MOJO_REACTOR=Mojo::Reactor::Poll matches the upstream networking tests and avoids an optional reactor dependency.

Recreate the exact module environment

From a PerlOnJava checkout with a built jperl launcher, this recipe downloads the unchanged upstream source. It uses newly created directories, not any investigator's local installation:

export JPERL="$PWD/jperl"
workdir=$(mktemp -d)
curl -fL https://cpan.org/authors/id/S/SR/SRI/Mojolicious-9.49.tar.gz -o "$workdir/Mojolicious-9.49.tar.gz"
shasum -a 256 "$workdir/Mojolicious-9.49.tar.gz"
tar -xzf "$workdir/Mojolicious-9.49.tar.gz" -C "$workdir"
export MOJOLIB="$workdir/Mojolicious-9.49/lib"
# Put the complete inline program above in repro.t.
timeout 60 perl -I"$MOJOLIB" repro.t > perl-result.log 2>&1
timeout 120 "$JPERL" -I"$MOJOLIB" repro.t > jvm-result.log 2>&1
timeout 120 "$JPERL" --interpreter -I"$MOJOLIB" repro.t > interpreter-result.log 2>&1

Archive SHA-256: 281933d4f9b821f669a3e93a466daaad5596443ea2cb167fa7c019752bce6d66.

Allow local socket creation. An OS/sandbox denial such as Can't create listen socket: Operation not permitted is a setup failure and must be resolved before comparing backends. The recorded behavioral comparisons were all made with loopback access permitted. No upstream source or test was changed, no compatibility shim was added, and no optional JSON XS dependency is needed for this request.

Exact results

Standard Perl and JVM, exit 0:

ok 1 - GET /nothing
ok 2 - 404 Not Found
1..2

Interpreter, exit 255, before any assertion completes:

Can't call method "server" on an undefined value at Mojo/Server/Daemon.pm line 55.

Both PerlOnJava runs also print existing experimental signature/@_ warnings from the bundled File/stat.pm at lines 198, 202, and 213. The JVM succeeds despite these warnings, so they do not by themselves explain the interpreter abort.

Earliest known source divergence

The unchanged Daemon start method reaches:

sub start {
  my $self = shift;
  my $loop = $self->ioloop;
  if (my $max = $self->max_clients) { $loop->max_connections($max) }
  # ...
  elsif (!@{$self->acceptors}) {
    $self->app->server($self);  # line 55: receiver of server() is undef
    $self->_listen($_) for @{$self->listen};
  }
  return $self;
}

The diagnostic concerns $self->app, not an undefined daemon or a remote HTTP status. Relevant upstream ownership paths:

# Mojo::Server
has app => sub { shift->build_app('Mojo::HelloWorld') };

# Test::Mojo
sub app {
  my ($self, $app) = @_;
  return $self->ua->server->app unless $app;
  $self->ua->server->app($app);
  return $self;
}

The failure is backend-specific on this source candidate. It may concern generated accessor arguments, application ownership/lifetime, or interpreter dispatch; those are hypotheses, not established root causes. Capturing the app before startup and comparing explicit versus default app construction are the next discriminating reductions.

Investigation already ruled out

An earlier reduction set inactivity_timeout(5) and caused a JVM client timeout while the first debug 404 page compiled. Trace output showed that the application did render 404 and subsequent cached requests succeeded. A later control with the upstream default timeout passed on JVM. Do not use that shortened-timeout experiment as proof of an HTTP semantics bug or a performance regression on the shared production host.

The full CPAN run 20261004-150842-64297 separately reported failures in t/mojolicious/proxy_app.t and t/mojolicious/restful_lite_app.t on the default/JVM acceptance path. Their causes remain unclassified. This interpreter startup failure has not been shown to explain them, and closing this ticket must not silently clear those qualification gaps.

Related work and duplicate check

Open and closed issues were searched for Test::Mojo and Daemon.pm on 2026-10-05; no matching issue was found. No fork, parser compilation failure, or #1269 behavior appears in the reduced program.

Acceptance criteria and next work

  • Reduce application loss/dispatch to a project-owned Perl regression where possible; validate it first on standard Perl and preserve the interpreter failure on the recorded parent.
  • Retain the unchanged module-level reproducer above as a focused integration check.
  • Fix the owning runtime/backend code, preserving all existing tests and weak-reference/DESTROY semantics.
  • Both backends pass the two assertions with the default timeout and local sockets enabled.
  • Check explicit app objects and default Mojolicious::Lite app construction; verify app identity survives daemon startup.
  • Run adjacent lifecycle/accessor regressions and the final unfiltered nice -n 19 make gate.
  • Retest original proxy/restful failures independently; report any residual root instead of assuming this fix covers them.

All decisive diagnostics, source excerpts, and reproducer code are embedded here. No investigator-local files are needed.

Activity

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

    area:backendJVM interpreter or execution-backend behaviorbugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions