Skip to content

Server cannot decode binary parameter #97

Closed

Description

@winder

I'm having trouble using binary parameters, I'm not sure what I'm doing wrong.

I have a parameter defined with:

    "note-prefix": {
      "type": "string",
      "format": "byte",
      "description": "Specifies a prefix which must be contained in the note field.",
      "name": "note-prefix",
      "in": "query"
    },

This generates a parameter object as expected with:

    NotePrefix *[]byte `json:"note-prefix,omitempty"`

Now I try to use the parameter by getting a base64 string echo "test" |base64, and url encoding it to get dGVzdAo%3D.

But the parameter isn't properly parsed:

$ curl -s "localhost:8980/transactions?note-prefix=dGVzdAo%3D" | json_pp
{
   "message" : "Invalid format for parameter note-prefix: error setting array element: error binding string parameter: can not bind to destination of type: uint8"
}

I'm hoping that this is user error, but it looks like an entry is missing from this:
https://github.com/deepmap/oapi-codegen/blob/88bfbcf8cc7a4c8bfa82c3f0a6cfd0eb1db34d63/pkg/runtime/bindstring.go#L50

Hoping that someone can confirm.

Activity

  1. winder commented on Apr 21, 2020

    @winder
    Author

    This seems to be a problem with BindQueryParameter for optional parameters, and I was able to detect the byte array type inside the IsNil check. But I wasn't sure how to turn this knowledge into a working version of BindQueryParameter.

    	} else {
    		// For optional parameters, we have an extra indirect. An optional
    		// parameter of type "int" will be *int on the struct. We pass that
    		// in by pointer, and have **int.
    
    		// If the destination, is a nil pointer, we need to allocate it.
    		if v.IsNil() {
    +			switch v.Kind() {
    +			case reflect.Slice:
    +				if v.Type() == reflect.TypeOf([]byte(nil)) {
    +					fmt.Println("byte array parameter detected")
    +				}
    +			}
    
    			t := v.Type()
    
    			newValue := reflect.New(t.Elem())
    			// for now, hang onto the output buffer separately from destination,
    			// as we don't want to write anything to destination until we can
    			// unmarshal successfully, and check whether a field is required.
    			output = newValue.Interface()
    		} else {
    			// If the destination isn't nil, just use that.
    			output = v.Interface()
    		}
    
    		// Get rid of that extra indirect as compared to the required case,
    		// so the code below doesn't have to care.
    		v = reflect.Indirect(reflect.ValueOf(output))
    	}
  2. stevenh commented on Mar 9, 2024

    @stevenh

    The issue seems to be that BindQueryParameter assumes that if the destination is a slice it's the target for individual query parameters, which is not the case for format byte which is expecting a single parameter stored. Unfortunately even with explode: false it still calls bindSplitPartsToDestinationArray which doesn't handle this case.

    We could update BindQueryParameter to treat a slice of uint8 aka byte as a special case, but not sure if that's backwards compatible.

  3. mromaszewicz commented on Feb 25, 2026

    @mromaszewicz
    Member

    Runtime fix is up in #98. The code generator still needs to be updated to emit calls to the new WithOptions functions with TypeHintBinary — tracked in oapi-codegen/oapi-codegen#2248.

  4. mromaszewicz commented on Feb 26, 2026

    @mromaszewicz
    Member

    This is now fixed in the runtime and released as v1.2.0. This PR in the main codegen incorporates these changes, and I've verified that binary parameters marshal correctly:
    oapi-codegen/oapi-codegen#2256

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions