Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Undefined array key "properties" when Model Policy uses custom Exception #963

Open
1 task done
mcpicoli opened this issue Mar 1, 2025 · 1 comment
Open
1 task done
Labels
bug Something isn't working triage

Comments

@mcpicoli
Copy link

mcpicoli commented Mar 1, 2025

Scribe version

5.0.0

PHP version

8.3.6

Laravel version

11.43.1

Scribe config

try_it_out.use_csrf => true

What happened?

If any methods in a Model Controller use a Policy via the Gate::allows() facade but throws a custom Exception, the OpenAPI specification generator bombs with the following:

ⓘ Generating OpenAPI specification

   ErrorException

  Undefined array key "properties"

  at vendor\knuckleswtf\scribe\src\Writing\OpenApiSpecGenerators\BaseGenerator.php:554
    550▕                     return [$k => $this->generateSchemaForResponseValue($v, $endpoint, "$path.$k")];
    551▕                 })->toArray();
    552▕             }
    553▕
  ➜ 554▕             $required = $this->filterRequiredResponseFields($endpoint, array_keys($schema['items']['properties']), $path);
    555▕             if ($required) {
    556▕                 $schema['required'] = $required;
    557▕             }
    558▕         }

  1   vendor\knuckleswtf\scribe\src\Writing\OpenApiSpecGenerators\BaseGenerator.php:554
      Illuminate\Foundation\Bootstrap\HandleExceptions::Illuminate\Foundation\Bootstrap\{closure}("Undefined array key "properties"", "D:\project\wemax-backend\vendor\knuckleswtf\scribe\src\Writing\OpenApiSpecGenerators\BaseGenerator.php")

  2   vendor\knuckleswtf\scribe\src\Writing\OpenApiSpecGenerators\BaseGenerator.php:514
      Knuckles\Scribe\Writing\OpenApiSpecGenerators\BaseGenerator::generateSchemaForResponseValue(Object(Knuckles\Camel\Output\OutputEndpointData), "errors.acesso")

The route is simple:

Route::get("/cliente", [ClienteController::class, "pesquisa"]); // search

The Controller method is also simple:

	/**
	 * @queryParam texto string Texto parcial de pesquisa. No-example
	 */
	public function pesquisa(Request $request)
	{
		$lista_validacao = [
			"texto"							=> ["nullable", "string", "min:1", "max:200"],
		];

		// Query Parameters
		$request->validate($lista_validacao);

		// Autorização
		if (!Gate::allows("pesquisar", Cliente::class))
		{
			throw new AcessoNegadoException(  // <----------- This causes the problem
				operacao: $nome_operacao,
			);
		}

		// Other Stuff not related
	}

The policy is also simple (only the relevant part pasted):

	public function pesquisar(User $user): bool
	{
		// Permissão do Operador
		if (
			$user->can(PermissoesOperador::CLIENTE_PESQUISA)
			|| $user->can(PermissoesOperador::SUPER)
		)
		{
			return true;
		}

		return false;
	}

The custom exception only reformats the fields of a base Exception to suit the project's frontend:

<?php

namespace App\Exceptions;

use App\Http\Responses\AcessoNegadoResponse;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;

class AcessoNegadoException extends \Exception
{
	public function __construct(
		protected string $operacao,

		$message = "",
		$code = 0,
		\Exception $previous = null,
	)
	{
		parent::__construct($message, $code, $previous);
	}

	/**
	 * Report the exception.
	 */
	public function report(): void
	{
		// Nada a Reportar
	}

	/**
	 * Render the exception as an HTTP response.
	 */
	public function render(Request $request) : Response|JsonResponse
	{
		if ($request->wantsJson())
		{
			return (new AcessoNegadoResponse(mensagem: $this->message, operacao: $this->operacao))->toResponse($request);
		}

		abort(403);
	}
}

(it works fine)

If the Gate check is changed to:

if (Gate::allows("pesquisar", Cliente::class))

instead of

if (!Gate::allows("pesquisar", Cliente::class))

(note the "!")
... then the OpenAPI specification generation does not fail anymore - but app logic is broken. If I add an "else" case to the inverted logic, the error is triggered again.

For now, the OpenAPI documentation simply is not required, so for now I simply ignore the error, but I want to know what's wrong with Scribe or if there is something inherently wrong with throwing custom access denied exceptions together with Scribe.

Docs

@mcpicoli mcpicoli added bug Something isn't working triage labels Mar 1, 2025
@mcpicoli
Copy link
Author

mcpicoli commented Mar 1, 2025

Obvious additional information:

If I disable the OpenAPI specification generation in the scribe.php configuration file, the error goes away.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working triage
Projects
None yet
Development

No branches or pull requests

1 participant