{"record":{"id":"7fb484053d75042f","repo":"dagger/dagger","slug":"type-json-stringify-typedef-has-already-been-r","errorCode":null,"errorMessage":"type ${JSON.stringify(typeDef)} has already been resolved, it should not be overwritten ; reference: ${JSON.stringify(reference)}","messagePattern":"type (.+?) has already been resolved, it should not be overwritten ; reference: (.+?)","errorType":"exception","errorClass":"IntrospectionError","httpStatus":null,"severity":"error","filePath":"sdk/typescript/src/module/introspector/typescript_module/typedef_utils.ts","lineNumber":38,"sourceCode":"  return true\n}\n\nexport function resolveTypeDef(\n  typeDef: TypeDef<TypeDefKind> | undefined,\n  reference: TypeDef<TypeDefKind>,\n): TypeDef<TypeDefKind> {\n  if (typeDef === undefined) {\n    return reference\n  }\n\n  if (typeDef.kind === TypeDefKind.ListKind) {\n    const listTypeDef = typeDef as TypeDef<TypeDefKind.ListKind>\n\n    listTypeDef.typeDef = resolveTypeDef(listTypeDef.typeDef, reference)\n    return listTypeDef\n  }\n\n  throw new IntrospectionError(\n    `type ${JSON.stringify(typeDef)} has already been resolved, it should not be overwritten ; reference: ${JSON.stringify(reference)}`,\n  )\n}\n","sourceCodeStart":20,"sourceCodeEnd":42,"githubUrl":"https://github.com/dagger/dagger/blob/82ba2681dbe30d3547a1dc50ea495900ab5b6047/sdk/typescript/src/module/introspector/typescript_module/typedef_utils.ts#L20-L42","documentation":"During TypeDef reference propagation, resolveTypeDef reached a TypeDef that already had its inner `typeDef` filled in, so resolving it again with the given reference would overwrite an already-resolved value. This is an internal invariant violation: it indicates a reference graph where the same TypeDef is being resolved twice or references were applied in the wrong order.","triggerScenarios":"A TypeDef structure is passed through propagateReferences/resolveTypeDef twice (e.g. the same object instance appears in two fields, or a cyclic/self-referential object causes a second traversal), so the leaf TypeDef already has a resolved inner type when resolution recurses into it.","commonSituations":"Modules with recursive object types (an object referencing itself), duplicated registration of the same class under two fields, or SDK-internal bugs when mutating shared TypeDef instances.","solutions":["Remove self-referential/cyclic type definitions between your @object classes; Dagger does not support recursive types.","Ensure each @object class field maps to a distinct TypeDef instance; avoid reusing one shared object across multiple fields.","Reproduce with a minimal module and, if it looks like an SDK bug, report it to dagger with the module source.","Upgrade the TypeScript SDK to the latest version, as this may be a fixed introspector regression."],"exampleFix":"// before\nclass Node { child?: Node } // recursive\n\n// after\nclass Child { name!: string }\nclass Node { child?: Child } // no self-reference","handlingStrategy":"validation","validationCode":"// reject recursive object graphs before registering\nfunction assertNoRecursion(root: Function, seen = new Set<Function>()): void {\n  if (seen.has(root)) throw new Error(`recursive type: ${root.name}`)\n  seen.add(root)\n  // walk fields' types and recurse for @object classes\n}","typeGuard":null,"tryCatchPattern":"try {\n  await dag.module().throwError()\n} catch (e) {\n  if (String(e).includes(\"has already been resolved\")) {\n    // indicates cyclic/self-referential type; refactor the object graph\n  }\n  throw e\n}","preventionTips":["Do not create self-referential or cyclic @object class types","Never reuse a single TypeDef-like shared object across multiple fields","Keep object graphs acyclic: parent -> child -> leaf"],"tags":["typescript","introspection","typedef","internal-invariant"],"backgroundTag":"typedef-already-resolved","analyzedSha":"82ba2681dbe30d3547a1dc50ea495900ab5b6047","analyzedAt":"2026-09-05T07:21:37.930Z","contentChangedAt":"2026-09-05T07:21:37.930Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}