gastownhall/beads · error
missing external ref for Linear issue %s
Error message
missing external ref for Linear issue %s
What it means
During Linear import/sync, when converting dependencies involving a project milestone, the code requires the milestone's epic external ref. If the resolved ref string is empty, this error aborts conversion for that issue, since a dependency cannot be recorded without a FromExternalID.
Source
Thrown at cmd/bd/linear.go:551
}
hooks.GenerateID = generateID
}
if opts.Milestones && st != nil {
hooks.AfterConvert = func(ctx context.Context, extIssue *tracker.TrackerIssue, conv *tracker.IssueConversion, ref string, _ *types.Issue, syncOpts tracker.SyncOptions) error {
li, ok := extIssue.Raw.(*linear.Issue)
if !ok || li == nil || li.ProjectMilestone == nil {
return nil
}
if syncOpts.DryRun || opts.DryRun {
return nil
}
milestoneRef, err := ensureLinearMilestoneEpic(ctx, st, li.ProjectMilestone, hookActor, generateID)
if err != nil {
return err
}
if strings.TrimSpace(ref) == "" {
return fmt.Errorf("missing external ref for Linear issue %s", extIssue.Identifier)
}
conv.Dependencies = append(conv.Dependencies, tracker.DependencyInfo{
FromExternalID: ref,
ToExternalID: milestoneRef,
Type: string(types.DepParentChild),
Source: tracker.DependencySourceParent,
})
return nil
}
}
return hooks
}
const linearMilestoneExternalRefPrefix = "linear:project-milestone:"
func linearMilestoneExternalRef(id string) string {
return linearMilestoneExternalRefPrefix + strings.TrimSpace(id)View on GitHub (pinned to 71377f2769)
Solutions
- Inspect the Linear issue's project milestone data for empty/blank identifiers
- Re-run the sync so ensureLinearMilestoneEpic recreates the milestone epic with a valid external ref
- Check for prior import failures that left the milestone epic without an external ref and repair or delete that epic record
Defensive patterns
Strategy: validation
Validate before calling
// before appending the dependency, verify the ref
if strings.TrimSpace(ref) == "" {
log.Printf("skipping dependency for %s: empty external ref", extIssue.Identifier)
return nil
} Type guard
func hasExternalRef(issue *types.Issue) bool {
return issue.ExternalRef != nil && strings.TrimSpace(*issue.ExternalRef) != ""
} Try / catch
// the sync pipeline returns this error directly; catch at the import boundary
if err := runLinearSync(ctx); err != nil {
if strings.Contains(err.Error(), "missing external ref") { /* log issue ID and continue/skip */ }
return err
} Prevention
- Validate Linear milestone payloads (non-empty IDs and refs) before conversion
- Repair or delete milestone epics left without external refs by failed imports
- Re-run sync after fixing upstream Linear data so refs are regenerated
When it happens
Trigger: Linear sync hits an issue whose milestone epic lookup/creation returned an empty ref string (e.g. ensureLinearMilestoneEpic returned empty without error due to unexpected data) while appending a parent-child dependency to conv.Dependencies.
Common situations: Linear workspace data quirks — milestone objects with empty identifiers; a partially completed import where the milestone epic was matched but ref assignment was skipped; custom sync scripts feeding unusual Linear payloads.
Related errors
- Linear project milestone is missing id
- generating Linear milestone epic ID: %w
- creating Linear milestone epic %q: %w
- searching local issues for Linear milestone %s: %w
- existing milestone metadata is not a JSON object: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/ee6641275f4de45c.
Report an issue: GitHub.