laravel/framework · error · InvalidArgumentException

Using three-part references is not supported, you may use…

Error message

Using three-part references is not supported, you may use `Schema::connection('{$segments[0]}')` instead.

What it means

Builder::parseSchemaAndTable() splits the reference on '.' and rejects anything with more than two segments - i.e. a three-part (catalog.schema.table) reference - with an InvalidArgumentException. Laravel's schema introspection is scoped to a single connection; cross-database references must go through a separate connection rather than a dotted string. The error message itself names the suggested fix using $segments[0].

Solutions

  1. Use Schema::connection($catalog)->... with the two-part (schema.table) or one-part (table) reference instead.
  2. Strip the leading catalog segment from your reference string before passing it to a Schema method.
  3. Normalise table names in configuration so they never carry the database/catalog prefix.

Example fix

// before - three-part reference throws
Schema::hasTable('inventory.public.products');

// after - switch connection and drop the catalog segment
Schema::connection('inventory')->hasTable('public.products');
// or, on the default schema:
Schema::connection('inventory')->hasTable('products');
Defensive patterns

Strategy: validation

Validate before calling

if (substr_count($reference, '.') > 1) {
    throw new \InvalidArgumentException(
        "Reference '{$reference}' has more than 2 segments; use Schema::connection() for cross-database access."
    );
}
Schema::hasTable($reference);

Type guard

function isParsableTableReference(string $reference): bool
{
    return substr_count($reference, '.') <= 1;
}

Try / catch

try {
    Schema::hasTable($reference);
} catch (\InvalidArgumentException $e) {
    if (str_contains($e->getMessage(), 'three-part references')) {
        [$connection, $rest] = explode('.', $reference, 2);
        return Schema::connection($connection)->hasTable($rest);
    }
    throw $e;
}

Prevention

When it happens

Trigger: Passing 'mydb.public.users' (or any reference with two dots) to any Builder method that parses schema/table: getColumns, getColumnListing, getColumnType, hasColumn, getIndexes, getForeignKeys, etc. Also triggered indirectly when a migration or model hands such a string to Schema::hasTable().

Common situations: Copying a SQL Server or MySQL cross-database query pattern into Laravel schema calls; reading table names from a config that includes the catalog; MySQL users who prefix with database name out of habit; refactoring a single-DB app into multi-DB and forgetting to switch connections.

Related errors


AI-assisted analysis of laravel/framework@e0f6eb3518 (2026-08-11). Data as JSON: /api/errors/b6bc5c33ac10dcff. Report an issue: GitHub.

Appendix: source

Thrown at src/Illuminate/Database/Schema/Builder.php:757

    {
        return $this->getCurrentSchemaListing()[0] ?? null;
    }

    /**
     * Parse the given database object reference and extract the schema and table.
     *
     * @param  string  $reference
     * @param  string|bool|null  $withDefaultSchema
     * @return array{string|null, string}
     *
     * @throws \InvalidArgumentException
     */
    public function parseSchemaAndTable($reference, $withDefaultSchema = null)
    {
        $segments = explode('.', $reference);

        if (count($segments) > 2) {
            throw new InvalidArgumentException(
                "Using three-part references is not supported, you may use `Schema::connection('{$segments[0]}')` instead."
            );
        }

        $table = $segments[1] ?? $segments[0];

        $schema = match (true) {
            isset($segments[1]) => $segments[0],
            is_string($withDefaultSchema) => $withDefaultSchema,
            $withDefaultSchema => $this->getCurrentSchemaName(),
            default => null,
        };

        return [$schema, $table];
    }

    /**
     * Get the database connection instance.

View on GitHub (pinned to e0f6eb3518)