{"record":{"id":"573fdbbfd4c9b21c","repo":"microsoft/aspire","slug":"aspirelist-must-be-resolved-before-it-can-be-serialized","errorCode":null,"errorMessage":"AspireList must be resolved before it can be serialized directly. Pass it to generated SDK methods instead of calling JSON.stringify directly.","messagePattern":"AspireList must be resolved before it can be serialized directly\\. Pass it to generated SDK methods instead of calling JSON\\.stringify directly\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.CodeGeneration.TypeScript/Resources/base.mts","lineNumber":813,"sourceCode":"\n    /**\n     * Converts the list to an array (creates a copy).\n     */\n    async toArray(): Promise<T[]> {\n        const handle = await this._ensureHandle();\n        return await this._client.invokeCapability('Aspire.Hosting/List.toArray', {\n            list: handle\n        }) as T[];\n    }\n\n    async toTransportValue(): Promise<MarshalledHandle> {\n        const handle = await this._ensureHandle();\n        return handle.toJSON();\n    }\n\n    toJSON(): MarshalledHandle {\n        if (!this._resolvedHandle) {\n            throw new Error(\n                'AspireList must be resolved before it can be serialized directly. ' +\n                'Pass it to generated SDK methods instead of calling JSON.stringify directly.'\n            );\n        }\n\n        return this._resolvedHandle.toJSON();\n    }\n}\n\nexport const AspireList = AspireListImpl;\n\n// ============================================================================\n// AspireDict<K, V> - Mutable Dictionary Wrapper\n// ============================================================================\n\n/**\n * Wrapper for a mutable .NET Dictionary<K, V>.\n * Provides object-like methods that invoke capabilities on the underlying collection.","sourceCodeStart":795,"sourceCodeEnd":831,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.CodeGeneration.TypeScript/Resources/base.mts#L795-L831","documentation":"AspireList.toJSON() refuses to serialize a list whose handle has not been resolved yet. Lists must be materialized through the app host (usually by passing them to generated SDK methods); calling JSON.stringify on an unresolved AspireList hits this error because there is no wire representation yet.","triggerScenarios":"Calling JSON.stringify(list) on a freshly created AspireList; embedding a list in an object passed to JSON.stringify or a logging call before any SDK method resolved it; awaiting nothing and reading toJSON directly.","commonSituations":"Debug logging of builder values before the app model runs; caching list payloads to disk; passing config structures containing AspireLists to third-party APIs that stringify them.","solutions":["Pass the AspireList to the generated SDK method that expects it instead of serializing it yourself.","Await the list's resolution (e.g. its toResolvedJSON()/ensure-handle path) before serializing if you need its representation.","For logging, print the list's identity/state rather than JSON.stringify.","Restructure the code so plain data (not AspireList) is what gets stringified."],"exampleFix":"// before\nconsole.log(JSON.stringify(myList)); // throws: unresolved\n\n// after\nconst resolved = await myList.toJSON(); // resolves handle first\nconsole.log(JSON.stringify(resolved));","handlingStrategy":"validation","validationCode":"// Resolve before serializing\nconst resolved = await myList.toJSON(); // or pass myList into the SDK method directly\nconst json = JSON.stringify(resolved);","typeGuard":"function isPlainSerializable(v: unknown): boolean {\n  return !(v instanceof Object && \"_resolvedHandle\" in v && (v as { _resolvedHandle?: unknown })._resolvedHandle === undefined);\n}","tryCatchPattern":"try {\n  log(JSON.stringify(value));\n} catch (e) {\n  if (e instanceof Error && e.message.includes(\"must be resolved before it can be serialized\")) {\n    log(\"[unresolved AspireList]\"); // log identity instead\n  } else throw e;\n}","preventionTips":["Pass AspireList values to generated SDK methods instead of stringifying them.","Await resolution before any toJSON/JSON.stringify call.","Never place Aspire builder values inside objects destined for third-party JSON APIs."],"tags":["serialization","typescript","async","unresolved-state"],"backgroundTag":"json-serialization-failed","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}