Skip to content

Conversation

simonjbeaumont
Copy link
Collaborator

@simonjbeaumont simonjbeaumont commented Jul 16, 2025

Motivation

When the generator is run as a command plugin on a correctly configured target but there are problems generating, there's a layer of error handling which is incorrect resulting in a poor user experience. For example, if the OpenAPI document contains a bad type like this...

components:
  schemas:
    BadIntHolder:
      type: object
      description: A value that has a bad typed int.
      properties:
        int:
          type: int
          description: A bad type

...then the command plugin shows the following output:

Considering target 'HelloWorldURLSessionClient':
- Trying OpenAPI code generation.
/Users/Si/work/code/swift-openapi-workspace/packages/swift-openapi-generator/Examples/hello-world-urlsession-client-example/Sources/HelloWorldURLSessionClient/openapi.yaml: error: Found neither a JSONType nor a Arr
ay<JSONType> in Document.components.schemas.Greeting.properties.i.type.

JSONType could not be decoded because:
Inconsistency encountered when parsing `[unknown object]`: Cannot initialize JSONType from invalid String value int.

Array<JSONType> could not be decoded because:
Expected value to be parsable as Sequence but it was not..
Error: /Users/Si/work/code/swift-openapi-workspace/packages/swift-openapi-generator/Examples/hello-world-urlsession-client-example/Sources/HelloWorldURLSessionClient/openapi.yaml: error: Found neither a JSONType no
r a Array<JSONType> in Document.components.schemas.Greeting.properties.i.type.

JSONType could not be decoded because:
Inconsistency encountered when parsing `[unknown object]`: Cannot initialize JSONType from invalid String value int.

Array<JSONType> could not be decoded because:
Expected value to be parsable as Sequence but it was not..
Swift OpenAPI Generator is running with the following configuration:
- OpenAPI document path: /Users/Si/work/code/swift-openapi-workspace/packages/swift-openapi-generator/Examples/hello-world-urlsession-client-example/Sources/HelloWorldURLSessionClient/openapi.yaml
- Configuration path: /Users/Si/work/code/swift-openapi-workspace/packages/swift-openapi-generator/Examples/hello-world-urlsession-client-example/Sources/HelloWorldURLSessionClient/openapi-generator-config.yaml
- Generator modes: types, client
- Access modifier: internal
- Naming strategy: idiomatic
- Name overrides: <none>
- Type overrides: <none>
- Feature flags: <none>
- Output file names: Types.swift, Client.swift
- Output directory: /Users/Si/work/code/swift-openapi-workspace/packages/swift-openapi-generator/Examples/hello-world-urlsession-client-example/Sources/HelloWorldURLSessionClient/GeneratedSources
- Diagnostics output path: <none - logs to stderr>
- Current directory: /Users/Si/work/code/swift-openapi-workspace/packages/swift-openapi-generator/Examples/hello-world-urlsession-client-example
- Plugin source: command
- Is dry run: false
- Additional imports: <none>
- Additional file comments: <none>
- Stopping because target isn't configured for OpenAPI code generation.
error: Targets with names HelloWorldURLSessionClient don't contain any config or OpenAPI document files with expected names. See documentation for details.

There are two issues with this:

  1. The final error is just plain wrong.
  2. Because the diagnostics are printed to stderr and the big info message to stdout they are ordered wrongly—you get the diagnostics before the message saying how the generator will run.

Modifications

  • Fix the categorisation of errors in the command plugin.
  • Print the big info message to stderr.

Result

  • Command plugin now correctly categorises misconfiguration errors vs other errors and provides more appropriate output on failure.

The above example now results in:

Considering target 'HelloWorldURLSessionClient':
- Trying OpenAPI code generation.
Swift OpenAPI Generator is running with the following configuration:
- OpenAPI document path: /Users/Si/work/code/swift-openapi-workspace/packages/swift-openapi-generator/Examples/hello-world-urlsession-client-example/Sources/HelloWorldURLSessionClient/openapi.yaml
- Configuration path: /Users/Si/work/code/swift-openapi-workspace/packages/swift-openapi-generator/Examples/hello-world-urlsession-client-example/Sources/HelloWorldURLSessionClient/openapi-generator-config.yaml
- Generator modes: types, client
- Access modifier: internal
- Naming strategy: idiomatic
- Name overrides: <none>
- Type overrides: <none>
- Feature flags: <none>
- Output file names: Types.swift, Client.swift
- Output directory: /Users/Si/work/code/swift-openapi-workspace/packages/swift-openapi-generator/Examples/hello-world-urlsession-client-example/Sources/HelloWorldURLSessionClient/GeneratedSources
- Diagnostics output path: <none - logs to stderr>
- Current directory: /Users/Si/work/code/swift-openapi-workspace/packages/swift-openapi-generator/Examples/hello-world-urlsession-client-example
- Plugin source: command
- Is dry run: false
- Additional imports: <none>
- Additional file comments: <none>/Users/Si/work/code/swift-openapi-workspace/packages/swift-openapi-generator/Examples/hello-world-urlsession-client-example/Sources/HelloWorldURLSessionClient/openapi.yaml: error: Found neither a JSONType nor a Array<JSONType> in Document.components.schemas.Greeting.properties.int.type.

JSONType could not be decoded because:
Inconsistency encountered when parsing `[unknown object]`: Cannot initialize JSONType from invalid String value int.

Array<JSONType> could not be decoded because:
Expected value to be parsable as Sequence but it was not..
Error: /Users/Si/work/code/swift-openapi-workspace/packages/swift-openapi-generator/Examples/hello-world-urlsession-client-example/Sources/HelloWorldURLSessionClient/openapi.yaml: error: Found neither a JSONType nor a Array<JSONType> in Document.components.schemas.Greeting.properties.int.type.

JSONType could not be decoded because:
Inconsistency encountered when parsing `[unknown object]`: Cannot initialize JSONType from invalid String value int.

Array<JSONType> could not be decoded because:
Expected value to be parsable as Sequence but it was not..
- OpenAPI code generation failed with error.
error: The generator failed to generate OpenAPI files for target 'HelloWorldURLSessionClient'.

Related issues

@simonjbeaumont simonjbeaumont requested a review from czechboy0 July 16, 2025 06:31
@simonjbeaumont simonjbeaumont added the 🔨 semver/patch No public API change. label Jul 16, 2025
@simonjbeaumont
Copy link
Collaborator Author

//cc @MaxDesiatov

Copy link
Contributor

@czechboy0 czechboy0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Copy link
Member

@MaxDesiatov MaxDesiatov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this actually output the validation error? I don't see that changed in the diff, but I'm not familiar with the code to say for sure

@simonjbeaumont
Copy link
Collaborator Author

simonjbeaumont commented Jul 16, 2025

@MaxDesiatov the validation output was always printed (it should have been in your output already, just way up because of the stderr/stdout flushing differences). You can see in the examples in the PR description that they were printed in both cases too. Now they'll be printed in the correct order and you'll see them right before the final error.

Would you mind running your repro against this branch to confirm?

@MaxDesiatov
Copy link
Member

I see, yes it's at the top, which I personally find unobvious. May I suggest that separating the error messages to be placed on adjacent lines? - OpenAPI code generation failed with error with actual error context dozens of lines above feels disconnected. If placing them on adjacent lines requires significant changes, maybe it could say "see the detailed error message above" or smth like that?

@simonjbeaumont
Copy link
Collaborator Author

@MaxDesiatov I'm just wanting to confirm things here... your comment on this PR says:

I see, yes it's at the top, which I personally find unobvious. May I suggest that separating the error messages to be placed on adjacent lines? - OpenAPI code generation failed with error with actual error context dozens of lines above feels disconnected.

To be clear, we have solved exactly that in this PR. The weird ordering was the use of both stdout and stderr. It should now be the case that the final output of the tool in this failure mode is an error that it couldn't generate and, right above that, will be the errors.

But... in your comment on the issue you say

No I never saw this in the output. That was the most misleading thing in the current diagnostic behavior. For some time I thought the generator couldn't discover the OpenAPI document at all.

I'm pretty sure that this PR addresses your issue but I'd like to make sure I haven't missed something before we cut a release 🙏

@MaxDesiatov
Copy link
Member

MaxDesiatov commented Jul 16, 2025

Sorry, the error message was there, but it was cut off because my terminal height was set to just a few lines. I didn't notice it because of the ordering. If changing from stdout to stderr fixes the ordering issue, that's much appreciated, thanks!

Comment on lines 84 to +85
if error.isMisconfigurationError {
print("- OpenAPI code generation failed with error.")
print("- Stopping because target isn't configured for OpenAPI code generation.")
Copy link
Contributor

@MahdiBM MahdiBM Jul 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not quite right though.

When isMisconfigurationError is true, It's pretty much certain that the user configured their target for openapi, but did it wrong.

When isMisconfigurationError is false, it can be either a misconfiguration or no-configuration.

Or at least that's what I intended with this code, IIRC.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not defending the existing message and handling. Just saying the new message/handling can also be improved.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's fair, how about we just tweak this one?

Suggested change
if error.isMisconfigurationError {
print("- OpenAPI code generation failed with error.")
print("- Stopping because target isn't configured for OpenAPI code generation.")
if error.isMisconfigurationError {
print("- Stopping because target is misconfigured for OpenAPI code generation.")

//cc @MahdiBM @czechboy0

@simonjbeaumont simonjbeaumont merged commit f876c5a into apple:main Jul 17, 2025
35 checks passed
simonjbeaumont added a commit that referenced this pull request Jul 23, 2025
…et argument (#798)

### Motivation

In #795 we adjusted the logic of the command plugin because errors were
not propagating properly. As a result, we regressed behaviour when the
command plugin was run without any `--target` argument. In this mode,
the plugin runs on all targets. When it detects a misconfigured target
it errors, as it should. However, the classification of misconfigured
target included targets that were not intended for code generation at
all, resulting in errors running the command plugin on packages with
others targets.

### Modifications

- Add command plugin generation step to integration test
- If the command plugin is running without a `--target` argument and
cannot find _any_ of the required files, skip that target.

### Result

- Manual code generation with the command plugin fixed for packages with
other targets.
- Fixes #797.

### Test Plan

This PR includes two commits. The first adds a step to the integration
test, which runs the command plugin on the integration test package.
This will fail in CI. Then the second commit will provide the fix, which
should pass in CI. The commits will then be squash merged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🔨 semver/patch No public API change.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Invalid openapi.yaml produces unexpected diagnostic message
4 participants