{"record":{"id":"5da1117f4d8e4596","repo":"twpayne/chezmoi","slug":"s-missing-external-type","errorCode":null,"errorMessage":"%s: missing external type","messagePattern":"(.+?): missing external type","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/chezmoi/sourcestate.go","lineNumber":2425,"sourceCode":"// readExternal reads an external and returns its SourceStateEntries.\nfunc (s *SourceState) readExternal(\n\tctx context.Context,\n\texternalRelPath RelPath,\n\tparentSourceRelPath SourceRelPath,\n\texternal *External,\n\toptions *ReadOptions,\n) (map[RelPath][]SourceStateEntry, error) {\n\tswitch external.Type {\n\tcase ExternalTypeArchive:\n\t\treturn s.readExternalArchive(ctx, externalRelPath, parentSourceRelPath, external, options)\n\tcase ExternalTypeArchiveFile:\n\t\treturn s.readExternalArchiveFile(ctx, externalRelPath, parentSourceRelPath, external, options)\n\tcase ExternalTypeFile:\n\t\treturn s.readExternalFile(ctx, externalRelPath, parentSourceRelPath, external, options)\n\tcase ExternalTypeGitRepo:\n\t\treturn nil, nil\n\tcase \"\":\n\t\treturn nil, fmt.Errorf(\"%s: missing external type\", externalRelPath)\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"%s: unknown external type: %s\", externalRelPath, external.Type)\n\t}\n}\n\n// readExternalArchive reads an external archive and returns its\n// SourceStateEntries.\nfunc (s *SourceState) readExternalArchive(\n\tctx context.Context,\n\texternalRelPath RelPath,\n\tparentSourceRelPath SourceRelPath,\n\texternal *External,\n\toptions *ReadOptions,\n) (map[RelPath][]SourceStateEntry, error) {\n\tdata, urlStr, format, err := s.readExternalArchiveData(ctx, externalRelPath, external, options)\n\tif err != nil {\n\t\treturn nil, err\n\t}","sourceCodeStart":2407,"sourceCodeEnd":2443,"githubUrl":"https://github.com/twpayne/chezmoi/blob/f901167e4685db90da56d6a2a19df642cb3e0247/internal/chezmoi/sourcestate.go#L2407-L2443","documentation":"Returned when an external entry in the source state has an empty type field. chezmoi's readExternal dispatch switch falls into the \"\" case because it cannot know how to interpret the entry without a type (archive, file, git-repo, etc.).","triggerScenarios":"An entry in .chezmoiexternal defines a url (or path) but omits the 'type' key, and the type cannot be inferred (e.g. no archive format guess possible for the given path/URL).","commonSituations":"Hand-written external config missing the type line; migration from an older chezmoi format; templating that dropped the type field.","solutions":["Add the missing type field to the external entry (archive, file, or git-repo)","Use the executable entry format (type = \"archive-file\" with executable) if that was intended","Validate .chezmoiexternal with chezmoi doctor or a dry-run apply"],"exampleFix":"// before\n[.oh-my-zsh]\n    url = \"https://github.com/ohmyzsh/ohmyzsh/archive/master.tar.gz\"\n// after\n[.oh-my-zsh]\n    type = \"archive\"\n    url = \"https://github.com/ohmyzsh/ohmyzsh/archive/master.tar.gz\"","handlingStrategy":"validation","validationCode":"// pre-validate external entries\nfor name, ext := range externals {\n    if ext.Type == \"\" { return fmt.Errorf(\"external %q is missing type\", name) }\n}","typeGuard":"func hasType(e External) bool { return e.Type != \"\" }","tryCatchPattern":null,"preventionTips":["Always set type explicitly in every external entry","Validate .chezmoiexternal in CI with a dry-run apply","Keep entries copied from docs complete, including type"],"tags":["config","external","missing-field"],"backgroundTag":"missing-external-type","analyzedSha":"f901167e4685db90da56d6a2a19df642cb3e0247","analyzedAt":"2026-09-01T18:16:41.508Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T01:17:15.007Z"}