{"record":{"id":"0d11a3f8f0d4f74e","repo":"different-ai/openwork","slug":"skill-create-response-was-incomplete","errorCode":null,"errorMessage":"Skill create response was incomplete.","messagePattern":"Skill create response was incomplete\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ee/apps/den-web/app/(den)/dashboard/_components/skill-data.tsx","lineNumber":132,"sourceCode":"export function useCreateSkill(pluginId: string) {\n  const queryClient = useQueryClient();\n\n  return useMutation({\n    mutationFn: async (draft: SkillDraft): Promise<DenSkill> => {\n      const { response, payload } = await requestJson(\n        \"/v1/config-objects\",\n        {\n          method: \"POST\",\n          body: JSON.stringify(createSkillPayload(pluginId, draft)),\n        },\n        15000,\n      );\n      if (!response.ok) {\n        throw getRequestError(payload, response, `Failed to create skill (${response.status}).`);\n      }\n      const skill = parseSkillResponse(payload);\n      if (!skill) {\n        throw new Error(\"Skill create response was incomplete.\");\n      }\n      return skill;\n    },\n    onSuccess: async () => {\n      await Promise.all([\n        queryClient.invalidateQueries({ queryKey: skillQueryKeys.all }),\n        queryClient.invalidateQueries({ queryKey: pluginQueryKeys.detail(pluginId) }),\n      ]);\n    },\n  });\n}\n\nexport function useUpdateSkill(pluginId: string) {\n  const queryClient = useQueryClient();\n\n  return useMutation({\n    mutationFn: async (input: { skillId: string; draft: SkillDraft }): Promise<DenSkill> => {\n      const { response, payload } = await requestJson(","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/ee/apps/den-web/app/(den)/dashboard/_components/skill-data.tsx#L114-L150","documentation":"useCreateSkill POSTs a new skill and, after a 2xx response, runs parseSkillResponse on the body. If the created-skill payload can't be parsed into the expected Skill shape, the mutation throws 'Skill create response was incomplete.' The create may actually have succeeded server-side; only the response parsing failed.","triggerScenarios":"POST /skills (plugin-scoped) returns ok but the body lacks fields parseSkillResponse requires (e.g. missing id, name, or steps array), or body is not a JSON record.","commonSituations":"API version drift after a server deploy changes the create-response shape; a gateway returns an empty 201 body; client parse expectations updated without matching server release.","solutions":["Check the network response body of the create call and compare to parseSkillResponse's required fields.","Align client parser with the current server response (update parseSkillResponse or the server to return required fields).","Before retrying, check whether the skill was actually created (duplicate-name risk) to avoid creating it twice.","If a proxy strips bodies, fix gateway config so JSON bodies pass through on 201."],"exampleFix":"// before\nconst skill = parseSkillResponse(payload);\nif (!skill) throw new Error(\"Skill create response was incomplete.\");\n// after\nconst skill = parseSkillResponse(payload);\nif (!skill) {\n  console.error(\"create payload:\", payload);\n  throw new Error(\"Skill create response was incomplete.\");\n}","handlingStrategy":"validation","validationCode":"function isCreatableSkillInput(v: unknown): boolean {\n  return isRecord(v) && typeof v.name === \"string\" && v.name.trim().length > 0;\n}","typeGuard":"function isSkillResponse(v: unknown): v is Skill {\n  return isRecord(v) && typeof v.id === \"string\";\n}","tryCatchPattern":"try {\n  await createSkill(input);\n} catch (e) {\n  if (e instanceof Error && e.message === \"Skill create response was incomplete.\") {\n    // verify whether the skill was actually created before retrying (avoid duplicates)\n    await queryClient.invalidateQueries({ queryKey: skillQueryKeys.all });\n  } else throw e;\n}","preventionTips":["After a parse failure, invalidate the list query before any retry to avoid duplicate creates","Add integration tests asserting the create-response shape","Keep server and client deployed in lockstep"],"tags":["api","mutation","schema"],"backgroundTag":"schema-validation-failed","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}