Skip to content

Fix serializeRecord to handle null/undefined additionalProperties#3575

Merged
v-jiaodi merged 4 commits intomainfrom
copilot/fix-serialize-record-null-support
Nov 4, 2025
Merged

Fix serializeRecord to handle null/undefined additionalProperties#3575
v-jiaodi merged 4 commits intomainfrom
copilot/fix-serialize-record-null-support

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Nov 4, 2025

Fix SerializeRecord to handle null and undefined for additional properties

Summary

This PR fixes an issue where generated serializer functions would fail when additionalProperties is null or undefined.

Problem

When TypeSpec generates TypeScript serializer functions for models with additional properties, it calls serializeRecord(item.additionalProperties). The serializeRecord function internally calls Object.keys(item), which throws a TypeError if item is null or undefined:

TypeError: Cannot convert undefined or null to object

Solution

Modified the code generation in buildSerializerFunction.ts to add a nullish coalescing operator (?? {}), so the generated code becomes:

...serializeRecord(item.additionalProperties ?? {})

This ensures that an empty object is passed to serializeRecord when additionalProperties is null or undefined, preventing the runtime error.

Changes Made

  1. ✅ Updated packages/typespec-ts/src/modular/serialization/buildSerializerFunction.ts to add ?? {} when generating serializeRecord calls (line 476)
  2. ✅ Updated test expectations in:
    • packages/typespec-ts/test/modularUnit/scenarios/models/serialization/additionalProperties.md (7 test cases)
    • packages/typespec-ts/test/modularUnit/scenarios/modelsGenerator/modelsGenerator.md (1 test case)
  3. ✅ Regenerated smoke test files to verify the fix works correctly in all generated code

Validation

  • ✅ All 384 unit tests pass
  • ✅ Code properly formatted with rush format
  • ✅ Code properly linted with npm run lint
  • ✅ Code review passed with no issues
  • ✅ Security scan passed (CodeQL)
  • ✅ Smoke test passed - all specs succeeded (8m 48s)

Fix Verification

The fix follows the suggestion from @MaryGao in the original issue and ensures that:

  • When additionalProperties is defined: normal behavior (serialize the properties)
  • When additionalProperties is null or undefined: safely pass an empty object to serializeRecord, which returns {}
  • No runtime errors occur

Generated Code Example

The smoke test regenerated files showing the fix working correctly:

// Before:
export function chatCompletionFunctionParametersSerializer(item: ChatCompletionFunctionParameters): any {
  return { ...serializeRecord(item.additionalProperties) };  // Would fail if null/undefined
}

// After:
export function chatCompletionFunctionParametersSerializer(item: ChatCompletionFunctionParameters): any {
  return { ...serializeRecord(item.additionalProperties ?? {}) };  // Safe with fallback
}
Original prompt

This section details on the original issue you should resolve

<issue_title>SerializeRecord does not support null and undefined for additional properties</issue_title>
<issue_description>https://github.com/Azure/autorest.typescript/blob/main/packages/typespec-ts/static/static-helpers/serialization/serialize-record.ts#L1

generate code link https://github.com/Azure/azure-sdk-for-js/blob/5fb686dc69ffda063beb131cc0fe110bed3cbcdc/sdk/redis/arm-rediscache/src/models/models.ts#L873:

export interface RedisCommonPropertiesRedisConfiguration {
  /** Specifies whether the RDB backup is enabled */
  rdbBackupEnabled?: string;
  /** Specifies the frequency for creating rdb backup in minutes. Valid values: (15, 30, 60, 360, 720, 1440) */
  rdbBackupFrequency?: string;
  /** Specifies the maximum number of snapshots for rdb backup */
  rdbBackupMaxSnapshotCount?: string;
  /** The storage account connection string for storing rdb file */
  rdbStorageConnectionString?: string;
  /** Specifies whether the aof backup is enabled */
  aofBackupEnabled?: string;
  /** First storage account connection string */
  aofStorageConnectionString0?: string;
  /** Second storage account connection string */
  aofStorageConnectionString1?: string;
  /** Value in megabytes reserved for fragmentation per shard */
  maxfragmentationmemoryReserved?: string;
  /** The eviction strategy used when your data won't fit within its memory limit. */
  maxmemoryPolicy?: string;
  /** Value in megabytes reserved for non-cache usage per shard e.g. failover. */
  maxmemoryReserved?: string;
  /** Value in megabytes reserved for non-cache usage per shard e.g. failover. */
  maxmemoryDelta?: string;
  /** The max clients config */
  readonly maxclients?: string;
  /** The keyspace events which should be monitored. */
  notifyKeyspaceEvents?: string;
  /** Preferred auth method to communicate to storage account used for data archive, specify SAS or ManagedIdentity, default value is SAS */
  readonly preferredDataArchiveAuthMethod?: string;
  /** Preferred auth method to communicate to storage account used for data persistence, specify SAS or ManagedIdentity, default value is SAS */
  preferredDataPersistenceAuthMethod?: string;
  /** Zonal Configuration */
  readonly zonalConfiguration?: string;
  /** Specifies whether the authentication is disabled. Setting this property is highly discouraged from security point of view; you should never disable authentication using this property! */
  authnotrequired?: string;
  /** SubscriptionId of the storage account for persistence (aof/rdb) using ManagedIdentity. */
  storageSubscriptionId?: string;
  /** Specifies whether AAD based authentication has been enabled or disabled for the cache */
  aadEnabled?: string;
  /** Additional properties */
  additionalProperties?: Record<string, any>;
}
export function redisCommonPropertiesRedisConfigurationSerializer(
  item: RedisCommonPropertiesRedisConfiguration,
): any {
  return {
    ...serializeRecord(item.additionalProperties),
    "rdb-backup-enabled": item["rdbBackupEnabled"],
    "rdb-backup-frequency": item["rdbBackupFrequency"],
    "rdb-backup-max-snapshot-count": item["rdbBackupMaxSnapshotCount"],
    "rdb-storage-connection-string": item["rdbStorageConnectionString"],
    "aof-backup-enabled": item["aofBackupEnabled"],
    "aof-storage-connection-string-0": item["aofStorageConnectionString0"],
    "aof-storage-connection-string-1": item["aofStorageConnectionString1"],
    "maxfragmentationmemory-reserved": item["maxfragmentationmemoryReserved"],
    "maxmemory-policy": item["maxmemoryPolicy"],
    "maxmemory-reserved": item["maxmemoryReserved"],
    "maxmemory-delta": item["maxmemoryDelta"],
    "notify-keyspace-events": item["notifyKeyspaceEvents"],
    "preferred-data-persistence-auth-method": item["preferredDataPersistenceAuthMethod"],
    authnotrequired: item["authnotrequired"],
    "storage-subscription-id": item["storageSubscriptionId"],
    "aad-enabled": item["aadEnabled"],
  };
}
```</issue_description>

## Comments on the Issue (you are @copilot in this section)

<comments>
<comment_new><author>@MaryGao</author><body>
fix:

...serializeRecord(item.additionalProperties ?? {}),

</comments>


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

…rties

Co-authored-by: v-jiaodi <80496810+v-jiaodi@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix SerializeRecord to support null and undefined Fix serializeRecord to handle null/undefined additionalProperties Nov 4, 2025
Copilot AI requested a review from v-jiaodi November 4, 2025 06:54
@v-jiaodi
Copy link
Copy Markdown
Member

v-jiaodi commented Nov 4, 2025

@copilot Run smoke test to fix ci under folder packages/typespec-test.

Co-authored-by: v-jiaodi <80496810+v-jiaodi@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Nov 4, 2025

@copilot Run smoke test to fix ci under folder packages/typespec-test.

Smoke test completed successfully. All specs passed and generated files have been updated with the fix. The change is in commit cf9fc76.

@v-jiaodi v-jiaodi marked this pull request as ready for review November 4, 2025 08:00
@v-jiaodi v-jiaodi merged commit 7c5a2be into main Nov 4, 2025
16 checks passed
@v-jiaodi v-jiaodi deleted the copilot/fix-serialize-record-null-support branch November 4, 2025 09:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SerializeRecord does not support null and undefined for additional properties

3 participants