{"record":{"id":"d16d86873db2afee","repo":"larksuite/cli","slug":"json-rawmessage-requires-an-explicit-shape","errorCode":null,"errorMessage":"json.RawMessage requires an explicit Shape","messagePattern":"json\\.RawMessage requires an explicit Shape","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shortcuts/common/typed_compile_data.go","lineNumber":138,"sourceCode":"\t\t\treturn nil, fmt.Errorf(\"integer field has incompatible schema constraint\")\n\t\t}\n\t\tshape = integerShape\n\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 != \"\" {","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/shortcuts/common/typed_compile_data.go#L120-L156","documentation":"During command registration the typed Data compiler walks the Go struct fields of a shortcut's Output.Data to derive a JSON ValueShape. json.RawMessage deliberately has no static schema — its content is arbitrary JSON — so the compiler refuses to guess one. It throws this error so the developer supplies an explicit Output.Data.Shape (or a narrower typed struct) instead.","triggerScenarios":"Declaring a shortcut Output.Data struct with a field of type json.RawMessage and compiling via compileData -> shapeForType when no explicit Output.Data.Shape is provided.","commonSituations":"Copying an API-response passthrough struct into typed Data; refactoring `interface{}` fields to json.RawMessage for safety; reusing an existing DTO that carries raw JSON blobs.","solutions":["Replace the json.RawMessage field with a concrete struct that models the actual JSON content.","If the content is genuinely arbitrary, change Output.Data to `any` (empty interface) so anyJSONShape is used.","Provide an explicit Output.Data.Shape so the compiler does not derive one from the Go type.","Use an Overrides entry or a custom Shape for just that field, keeping other fields inferred."],"exampleFix":"// before\ntype Data struct {\n    Extra json.RawMessage `json:\"extra\"`\n}\n\n// after\ntype ExtraPayload struct {\n    Kind string `json:\"kind\"`\n    Size int    `json:\"size\"`\n}\ntype Data struct {\n    Extra ExtraPayload `json:\"extra\"`\n}","handlingStrategy":"validation","validationCode":"func usesRawMessage(t reflect.Type) bool {\n    if t == reflect.TypeFor[json.RawMessage]() { return true }\n    switch t.Kind() {\n    case reflect.Struct:\n        for i := 0; i < t.NumField(); i++ {\n            if usesRawMessage(t.Field(i).Type) { return true }\n        }\n    case reflect.Slice, reflect.Array, reflect.Pointer:\n        return usesRawMessage(t.Elem())\n    }\n    return false\n}\n// fail registration early if usesRawMessage(reflect.TypeFor[Data]())","typeGuard":"func isRawMessage(t reflect.Type) bool { return t == reflect.TypeFor[json.RawMessage]() }","tryCatchPattern":null,"preventionTips":["Never put json.RawMessage in typed Output.Data structs; use `any` Data or concrete types.","Keep passthrough DTOs and typed Data definitions in separate types.","Run the shortcut registration in a quick smoke test so compile errors surface in CI."],"tags":["go","schema","compile-time","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"}