smithy-translate icon indicating copy to clipboard operation
smithy-translate copied to clipboard

Crash when encountering an Operation with no output

Open jessbowers opened this issue 3 months ago • 1 comments

Given this smithy:

$version: "2"

namespace test

use alloy.proto#protoEnabled

@protoEnabled
service Foo {
    operations: [
        BarNoOutput
    ]
}

operation BarNoOutput {
    input := {
        value: String
    }
}

Running smithy translate to output protobuf fails like this:

smithytranslate smithy-to-proto --input ./smithy/foo.smithy ./out/proto
Exception in thread "main" java.util.NoSuchElementException: No value present
	at java.base/java.util.Optional.get(Optional.java:143)
	at smithytranslate.proto3.internals.Compiler$rpcVisitor$.operationShape(Compiler.scala:514)
	at smithytranslate.proto3.internals.Compiler$rpcVisitor$.operationShape(Compiler.scala:510)
	at software.amazon.smithy.model.shapes.OperationShape.accept(OperationShape.java:76)
	at smithytranslate.proto3.internals.Compiler$topLevelDefsVisitor$.$anonfun$serviceShape$3(Compiler.scala:254)
	at scala.collection.immutable.List.flatMap(List.scala:294)
	at smithytranslate.proto3.internals.Compiler$topLevelDefsVisitor$.serviceShape(Compiler.scala:254)
	at smithytranslate.proto3.internals.Compiler$topLevelDefsVisitor$.serviceShape(Compiler.scala:215)
	at software.amazon.smithy.model.shapes.ServiceShape.accept(ServiceShape.java:90)
	at smithytranslate.proto3.internals.Compiler.$anonfun$compile$5(Compiler.scala:117)
	at scala.collection.immutable.List.flatMap(List.scala:294)
	at smithytranslate.proto3.internals.Compiler.$anonfun$compile$4(Compiler.scala:115)
	at scala.collection.StrictOptimizedIterableOps.flatMap(StrictOptimizedIterableOps.scala:118)
	at scala.collection.StrictOptimizedIterableOps.flatMap$(StrictOptimizedIterableOps.scala:105)
	at scala.collection.immutable.HashMap.flatMap(HashMap.scala:39)
	at smithytranslate.proto3.internals.Compiler.compile(Compiler.scala:114)
	at smithytranslate.proto3.SmithyToProtoCompilerInterface.compile(SmithyToProtoCompiler.scala:34)
	at smithytranslate.runners.Proto$.run(Proto.scala:78)
	at smithytranslate.runners.Proto$.runProto(Proto.scala:61)
	at smithytranslate.cli.Main$$anonfun$$lessinit$greater$1.apply(Main.scala:80)
	at smithytranslate.cli.Main$$anonfun$$lessinit$greater$1.apply(Main.scala:49)
	at scala.Function1.$anonfun$andThen$1(Function1.scala:87)
	at scala.Function1.$anonfun$andThen$1(Function1.scala:87)
	at cats.data.Validated.andThen(Validated.scala:727)
	at com.monovore.decline.Parser$Accumulator$Validate.$anonfun$mapValidated$1(Parser.scala:413)
	at scala.Function1.$anonfun$andThen$1(Function1.scala:87)
	at cats.data.Validated.andThen(Validated.scala:727)
	at com.monovore.decline.Result.$anonfun$mapValidated$2(Result.scala:13)
	at cats.instances.Function0Instances$$anon$4.$anonfun$map$1(function.scala:100)
	at com.monovore.decline.Parser.evalResult(Parser.scala:30)
	at com.monovore.decline.Parser.$anonfun$consumeAll$3(Parser.scala:107)
	at scala.util.Either.flatMap(Either.scala:360)
	at com.monovore.decline.Parser.$anonfun$consumeAll$1(Parser.scala:107)
	at scala.Option.map(Option.scala:242)
	at com.monovore.decline.Parser.consumeAll(Parser.scala:106)
	at com.monovore.decline.Parser.apply(Parser.scala:19)
	at com.monovore.decline.Command.parse(opts.scala:20)
	at smithytranslate.cli.CommandApp.main(CommandApp.scala:81)
	at smithytranslate.cli.Main.main(Main.scala)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:569)
	at coursier.bootstrap.launcher.a.a(Unknown Source)
	at coursier.bootstrap.launcher.Launcher.main(Unknown Source)

This fails validation if I add @grpc trait to the service, which gives the clue: the service must have an output.

Expected: validation error (or even better: assume Unit for output type)

jessbowers avatar Sep 23 '25 21:09 jessbowers

I don't recall the reason for preventing operations without an output (for reference, operations with no output are equivalent to Unit output in Smithy, in other words Unit is implied if no explicit type is provided).

It seems like we could use something like: https://protobuf.dev/reference/protobuf/google.protobuf/#empty

lewisjkl avatar Sep 23 '25 22:09 lewisjkl