Is there an existing issue for this?
Current behavior
When a property is decorated with @ApiProperty({ oneOf: [...], nullable: true }), the generated OpenAPI schema retains a contradictory type: "object" alongside the oneOf combinator. The type comes from reflect-metadata, which emits Object for any union type that TypeScript can't represent as a single class (e.g. string | number | null).
Source (latest master / 11.4.3): lib/services/schema-object-factory.ts:319-336
const schemaCombinators = ['oneOf', 'anyOf', 'allOf'];
const declaredSchemaCombinator = schemaCombinators.find(
(combinator) => combinator in property
);
if (declaredSchemaCombinator) {
const schemaObjectMetadata = property as SchemaObjectMetadata;
if (
schemaObjectMetadata?.type === 'array' ||
schemaObjectMetadata.isArray
) {
// ...
} else if (!schemaObjectMetadata['nullable']) {
delete schemaObjectMetadata.type;
}
}
When nullable: true, the inferred type is intentionally kept. PR #3784 introduced that retention so allOf could combine with { nullable: true, type: 'X' }. But for oneOf over primitives the retained type: "object" is wrong — the property is not an object, and the resulting schema is unsatisfiable.
This is related to but not the same as #3549 (which was about oneOf with $ref always referencing Object). #3549 was closed by PR #3781, which was reverted same-day in PR #3856. The general "oneOf keeps inferred type" pattern is still present whenever nullable: true is set.
Minimum reproduction code
https://gist.github.com/nrutman/a4b4605164938dbd055040c89976c829
Steps to reproduce
- Install
@nestjs/swagger@11.4.3 and the deps from the gist.
- Decorate a DTO property with
oneOf + nullable: true over primitive branches.
- Generate the OpenAPI document.
- Observe
type: "object" alongside the oneOf.
Expected behavior
type inferred from reflect-metadata should be dropped whenever any of oneOf / anyOf / allOf is declared, regardless of nullable. The nullable flag should be preserved on its own (it's documented inline in OAS 3.0 alongside any schema), but it should not gate the deletion of an inferred-only type field.
A possible fix: only retain type when it was explicitly set in the @ApiProperty options. The factory currently doesn't distinguish user-provided type from reflect-metadata-inferred type, so the safest change is to delete type for any of the combinator cases and require the user to re-add it explicitly when they want it (matching pre-nullable-aware behavior).
A user-side workaround that produces a valid schema today is to drop the top-level nullable and push nullable: true into each oneOf branch:
@ApiProperty({
oneOf: [
{ type: "string", nullable: true },
{ type: "number", nullable: true },
],
})
value!: string | number | null;
Package version
11.4.3
NestJS version
11.1.20
Node.js version
22.22.2
In which operating systems have you tested?
Other
Related: #3549, #3274, #3781, #3784, #3856.
Is there an existing issue for this?
Current behavior
When a property is decorated with
@ApiProperty({ oneOf: [...], nullable: true }), the generated OpenAPI schema retains a contradictorytype: "object"alongside theoneOfcombinator. Thetypecomes fromreflect-metadata, which emitsObjectfor any union type that TypeScript can't represent as a single class (e.g.string | number | null).Source (latest
master/11.4.3):lib/services/schema-object-factory.ts:319-336When
nullable: true, the inferredtypeis intentionally kept. PR #3784 introduced that retention soallOfcould combine with{ nullable: true, type: 'X' }. But foroneOfover primitives the retainedtype: "object"is wrong — the property is not an object, and the resulting schema is unsatisfiable.This is related to but not the same as #3549 (which was about
oneOfwith$refalways referencingObject). #3549 was closed by PR #3781, which was reverted same-day in PR #3856. The general "oneOfkeeps inferred type" pattern is still present whenevernullable: trueis set.Minimum reproduction code
https://gist.github.com/nrutman/a4b4605164938dbd055040c89976c829
Steps to reproduce
@nestjs/swagger@11.4.3and the deps from the gist.oneOf+nullable: trueover primitive branches.type: "object"alongside theoneOf.Expected behavior
typeinferred fromreflect-metadatashould be dropped whenever any ofoneOf/anyOf/allOfis declared, regardless ofnullable. Thenullableflag should be preserved on its own (it's documented inline in OAS 3.0 alongside any schema), but it should not gate the deletion of an inferred-onlytypefield.A possible fix: only retain
typewhen it was explicitly set in the@ApiPropertyoptions. The factory currently doesn't distinguish user-providedtypefrom reflect-metadata-inferredtype, so the safest change is to deletetypefor any of the combinator cases and require the user to re-add it explicitly when they want it (matching pre-nullable-aware behavior).A user-side workaround that produces a valid schema today is to drop the top-level
nullableand pushnullable: trueinto eachoneOfbranch:Package version
11.4.3
NestJS version
11.1.20
Node.js version
22.22.2
In which operating systems have you tested?
Other
Related: #3549, #3274, #3781, #3784, #3856.