{"record":{"id":"75c0489eca134b90","repo":"larksuite/cli","slug":"byte-slice-or-array-s-requires-an-explicit-shape","errorCode":null,"errorMessage":"byte slice or array %s requires an explicit Shape","messagePattern":"byte slice or array (.+?) requires an explicit Shape","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shortcuts/common/typed_compile_data.go","lineNumber":141,"sourceCode":"\tcase reflect.Float32, reflect.Float64:\n\t\tnumberShape := typedNumberShape{Minimum: schema.minimum, Maximum: schema.maximum}\n\t\tfor _, raw := range schema.enum {\n\t\t\tv, err := parseFiniteFloatBits(raw, baseType.Bits())\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"enum value %q is not a finite number\", raw)\n\t\t\t}\n\t\t\tnumberShape.Enum = append(numberShape.Enum, v)\n\t\t}\n\t\tif hasStringConstraints(schema) || hasItemConstraints(schema) || schema.format != \"\" {\n\t\t\treturn nil, fmt.Errorf(\"number field has incompatible schema constraint\")\n\t\t}\n\t\tshape = numberShape\n\tcase reflect.Slice, reflect.Array:\n\t\tif baseType == jsonRawMessageType {\n\t\t\treturn nil, fmt.Errorf(\"json.RawMessage requires an explicit Shape\")\n\t\t}\n\t\tif baseType.Elem().Kind() == reflect.Uint8 {\n\t\t\treturn nil, fmt.Errorf(\"byte slice or array %s requires an explicit Shape\", baseType)\n\t\t}\n\t\tif len(schema.enum) > 0 || hasStringConstraints(schema) || hasNumberConstraints(schema) || schema.format != \"\" {\n\t\t\treturn nil, fmt.Errorf(\"array field has incompatible schema constraint\")\n\t\t}\n\t\telementSchema := schemaTag{required: true}\n\t\telementShape, err := shapeForType(baseType.Elem(), elementSchema, input, active)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"array item: %w\", err)\n\t\t}\n\t\tshape = typedArrayShape{Items: elementShape, MinItems: schema.minItems, MaxItems: schema.maxItems}\n\tcase reflect.Struct:\n\t\tif implementsCustomEncoding(baseType) {\n\t\t\treturn nil, fmt.Errorf(\"custom JSON type %s requires an explicit Shape\", baseType)\n\t\t}\n\t\tif len(schema.enum) > 0 || hasStringConstraints(schema) || hasNumberConstraints(schema) || hasItemConstraints(schema) || schema.format != \"\" {\n\t\t\treturn nil, fmt.Errorf(\"object field has incompatible schema constraint\")\n\t\t}\n\t\tobject, err := compileStructShape(baseType, input, baseType.String(), active)","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/shortcuts/common/typed_compile_data.go#L123-L159","documentation":"The shape compiler cannot decide how []byte should appear in JSON: encoding/json base64-encodes byte slices, which rarely matches what a Lark API field actually expects. Rather than silently emit a base64 string schema, shapeForType rejects byte slices/arrays and asks for an explicit Shape or a declared string field.","triggerScenarios":"A Data struct field typed []byte, [N]byte, [][]byte, or any slice/array whose element kind is Uint8 reaches shapeForType via collectArgFields or compileStructShape during registration.","commonSituations":"Fields meant to hold file content, tokens, or binary IDs modeled as []byte; porting code where encoding/json's base64 behavior was relied on; dataclasses generated from OpenAPI binary formats.","solutions":["Change the field type to string if the API expects plain text/IDs.","If base64 is correct, declare the field as string and encode bytes yourself before producing Data.","Supply an explicit Output.Data.Shape describing the field as a string (or array of integers) shape.","Wrap bytes in a struct implementing encoding.TextMarshaler only if you also give an explicit Shape — custom-encoding types are likewise rejected."],"exampleFix":"// before\ntype Data struct {\n    Content []byte `json:\"content\"`\n}\n\n// after\ntype Data struct {\n    Content string `json:\"content\"` // base64-encode before filling\n}","handlingStrategy":"validation","validationCode":"func hasByteSlice(t reflect.Type) bool {\n    for t.Kind() == reflect.Pointer { t = t.Elem() }\n    switch t.Kind() {\n    case reflect.Slice, reflect.Array:\n        if t.Elem().Kind() == reflect.Uint8 { return true }\n        return hasByteSlice(t.Elem())\n    case reflect.Struct:\n        for i := 0; i < t.NumField(); i++ {\n            if hasByteSlice(t.Field(i).Type) { return true }\n        }\n    }\n    return false\n}","typeGuard":"func isByteSlice(t reflect.Type) bool {\n    return (t.Kind() == reflect.Slice || t.Kind() == reflect.Array) && t.Elem().Kind() == reflect.Uint8\n}","tryCatchPattern":null,"preventionTips":["Model binary API fields as string and encode (base64/hex) explicitly before filling Data.","Do not rely on encoding/json's implicit base64 of []byte in wire structs.","Add a unit test that constructs the shortcut command set so registration-time compile errors fail the build."],"tags":["go","byte-slice","schema","typed-data"],"backgroundTag":"explicit-shape-required","analyzedSha":"7fd6ef3c07182257ce776cdc5a614e122d5bd4b3","analyzedAt":"2026-09-04T21:17:44.649Z","contentChangedAt":"2026-09-04T21:17:44.649Z","schemaVersion":2},"datasetVersion":"2026-09-12T02:17:10.037Z"}