rectorphp/rector · error · ShouldNotHappenException

File object is missing. Make sure you call $this->currentFil

Error message

File object is missing. Make sure you call $this->currentFileProvider->setFile(...) before traversing.

What it means

AbstractRector::getFile() proxies CurrentFileProvider::getFile(). The provider is populated by the process pipeline (CurrentFileProvider->setFile(...) before each file is traversed). Calling getFile() outside that window — before traversal started or in a context that never set a file — yields null and throws ShouldNotHappenException telling you to call setFile() first.

Source

Thrown at src/Rector/AbstractRector.php:164

            // notify this rule changed code
            $rectorWithLineChange = new RectorWithLineChange(static::class, $originalNode->getStartLine());
            $this->file->addRectorClassWithLine($rectorWithLineChange);
            return $refactoredNodeOrState;
        }
        return $this->postRefactorProcess($originalNode, $node, $refactoredNodeOrState, $filePath);
    }
    /**
     * @return mixed[]|int|\PhpParser\Node|null
     */
    final public function leaveNode(Node $node)
    {
        return null;
    }
    protected function getFile(): File
    {
        $file = $this->currentFileProvider->getFile();
        if (!$file instanceof File) {
            throw new ShouldNotHappenException('File object is missing. Make sure you call $this->currentFileProvider->setFile(...) before traversing.');
        }
        return $file;
    }
    protected function isName(Node $node, string $name): bool
    {
        return $this->nodeNameResolver->isName($node, $name);
    }
    /**
     * @param string[] $names
     */
    protected function isNames(Node $node, array $names): bool
    {
        return $this->nodeNameResolver->isNames($node, $names);
    }
    /**
     * Some nodes have always-known string name. This makes PHPStan smarter.
     * @see https://phpstan.org/writing-php-code/phpdoc-types#conditional-return-types
     *

View on GitHub (pinned to 408fcb0ff1)

Solutions

  1. Only call getFile() inside refactor()/node callbacks, i.e. during an actual traversal
  2. For tests, use the standard AbstractRectorTestCase harness (it sets the provider), or set CurrentFileProvider->setFile(new File($path, $content)) before invoking the rule
  3. Lazily resolve the file at use time instead of storing it in the constructor

Example fix

// before
protected function configure(): void
{
    $this->filePath = $this->getFile()->getFilePath(); // no file yet
}

// after: resolve lazily inside the node callback
public function refactor(Node $node): ?Node
{
    $filePath = $this->getFile()->getFilePath();
    // ...
}
Defensive patterns

Strategy: validation

Validate before calling

// in tests driving a rule directly
$file = new \Rector\FileSystem\File(__DIR__ . '/Fixture.php', file_get_contents(__DIR__ . '/Fixture.php'));
$currentFileProvider->setFile($file);

$result = $rectorRule->refactor($node);

Type guard

function hasCurrentFile(\Rector\FileSystem\CurrentFileProvider $provider): bool
{
    return $provider->getFile() instanceof \Rector\FileSystem\File;
}

Prevention

When it happens

Trigger: Unit tests that instantiate the rule and invoke refactor($node) directly; a rule calling $this->getFile() (or $this->file) from a constructor, configure(), or getRuleDefinition(); dry-run code paths that traverse cached/unchanged files without registering a File object.

Common situations: Fast unit tests bypassing AbstractRectorTestCase; rules that cache the file path eagerly at construction; a custom runner script that calls the traverser without the surrounding ProcessCommand lifecycle.

Related errors


AI-assisted analysis of rectorphp/rector@408fcb0ff1 (2026-08-21). Data as JSON: /api/errors/84a4216e31088929. Report an issue: GitHub.