{"record":{"id":"69cb9253bb0bf434","repo":"larksuite/cli","slug":"schema-spec-has-neither-type-nor-raw","errorCode":null,"errorMessage":"schema spec has neither Type nor Raw","messagePattern":"schema spec has neither Type nor Raw","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/event/catalog/compile.go","lineNumber":272,"sourceCode":"\t\treturn s.Native, true\n\t}\n\tif s.Custom != nil {\n\t\treturn s.Custom, false\n\t}\n\treturn nil, false\n}\n\n// renderSpec produces a JSON Schema from Type (reflected) or Raw (copied).\nfunc renderSpec(s *SchemaSpec) (json.RawMessage, error) {\n\tif s.Type != nil {\n\t\treturn schemas.FromType(s.Type), nil\n\t}\n\tif len(s.Raw) > 0 {\n\t\tbuf := make(json.RawMessage, len(s.Raw))\n\t\tcopy(buf, s.Raw)\n\t\treturn buf, nil\n\t}\n\treturn nil, errors.New(\"schema spec has neither Type nor Raw\")\n}\n\n// isPlaceholderSchema rejects declarations whose schema decodes but describes\n// nothing: an empty document, empty object, or null. Per-declaration checks\n// only see \"raw bytes are non-empty\" — this closes that gap.\nfunc isPlaceholderSchema(schema json.RawMessage) bool {\n\ttrimmed := bytes.TrimSpace(schema)\n\tif len(trimmed) == 0 {\n\t\treturn true\n\t}\n\tif bytes.Equal(trimmed, []byte(\"null\")) || bytes.Equal(trimmed, []byte(\"{}\")) {\n\t\treturn true\n\t}\n\tvar asMap map[string]json.RawMessage\n\tif err := json.Unmarshal(trimmed, &asMap); err == nil && len(asMap) == 0 {\n\t\treturn true\n\t}\n\treturn false","sourceCodeStart":254,"sourceCodeEnd":290,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/internal/event/catalog/compile.go#L254-L290","documentation":"renderSpec returns this error when a schema spec defines neither Type nor Raw — there is nothing to render into JSON Schema. resolveSchemaJSON calls renderSpec, and the caller's surrounding per-declaration checks only verify raw bytes are non-empty, so this check closes the gap of a decodes-but-describes-nothing spec. Compile ultimately surfaces it inside the aggregated 'event catalog rejected' message.","triggerScenarios":"Declaring an event catalog schema spec as an empty &Schema{} (zero-value: no Type set, len(Raw)==0), then compiling the catalog.","commonSituations":"Copied a declaration and forgot to fill the schema; a refactoring dropped the Type field; generated specs produced zero-value schema structs.","solutions":["Set Schema.Type (e.g. \"object\") with properties, or","Provide Schema.Raw with a valid pre-built JSON schema document","Re-run catalog compilation to confirm the declaration passes"],"exampleFix":"// before\nSchema: &catalog.Schema{}\n// after\nSchema: &catalog.Schema{Type: \"object\"} // or Schema{Raw: json.RawMessage(`{\"type\":\"object\"}`)}","handlingStrategy":"validation","validationCode":"if spec.Type == \"\" && len(spec.Raw) == 0 {\n    return fmt.Errorf(\"schema spec for %q needs Type or Raw\", key)\n}","typeGuard":"func hasRenderableSchema(s *catalog.SchemaSpec) bool { return s != nil && (s.Type != \"\" || len(s.Raw) > 0) }","tryCatchPattern":"buf, err := resolveSchemaJSON(spec)\nif err != nil {\n    // spec has neither Type nor Raw — supply one before compiling\n}","preventionTips":["Always set Type or Raw when declaring a schema","Copy full declarations, not zero-value struct literals","Add a unit test compiling every declared schema","Reject empty specs at declaration-construction time"],"tags":["events","schema","catalog"],"backgroundTag":"schema-validation-failed","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"}