{"record":{"id":"ba88f497a30d8ec9","repo":"gastownhall/beads","slug":"empty-timestamp","errorCode":null,"errorMessage":"empty timestamp","messagePattern":"empty timestamp","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/jira/refs.go","lineNumber":42,"sourceCode":"\n\treturn true\n}\n\n// ExtractJiraKey extracts the Jira issue key from an external_ref URL.\n// For example, \"https://company.atlassian.net/browse/PROJ-123\" returns \"PROJ-123\".\nfunc ExtractJiraKey(externalRef string) string {\n\tidx := strings.LastIndex(externalRef, \"/browse/\")\n\tif idx == -1 {\n\t\treturn \"\"\n\t}\n\treturn externalRef[idx+len(\"/browse/\"):]\n}\n\n// ParseTimestamp parses Jira's timestamp format into a time.Time.\n// Jira uses ISO 8601 with timezone: 2024-01-15T10:30:00.000+0000 or 2024-01-15T10:30:00.000Z\nfunc ParseTimestamp(ts string) (time.Time, error) {\n\tif ts == \"\" {\n\t\treturn time.Time{}, fmt.Errorf(\"empty timestamp\")\n\t}\n\n\t// Try common formats\n\tformats := []string{\n\t\t\"2006-01-02T15:04:05.000-0700\",\n\t\t\"2006-01-02T15:04:05.000Z\",\n\t\t\"2006-01-02T15:04:05-0700\",\n\t\t\"2006-01-02T15:04:05Z\",\n\t\ttime.RFC3339,\n\t\ttime.RFC3339Nano,\n\t}\n\n\tfor _, format := range formats {\n\t\tif t, err := time.Parse(format, ts); err == nil {\n\t\t\treturn t, nil\n\t\t}\n\t}\n","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/jira/refs.go#L24-L60","documentation":"ParseTimestamp rejects an empty string input before attempting any format parsing. Jira timestamps are ISO 8601 strings; an empty value means the upstream JSON field was absent, null, or an empty string, and no meaningful time can be produced. The zero time.Time and this error are returned to all callers (FetchIssueTimestamp, jiraToTrackerIssue, anonymous closures).","triggerScenarios":"ParseTimestamp(\"\") is called — i.e. the Jira issue JSON had an empty/missing timestamp field (e.g. updated, created, or a custom field) passed through directly.","commonSituations":"Jira fields that are legitimately unset (issue never updated in some views, empty custom datetime field); JSON unmarshaling into a string field that was null; older Jira Server versions omitting fields the Cloud API returns; mapping code not checking for null before calling ParseTimestamp.","solutions":["Check the field is non-empty before calling ParseTimestamp and handle the unset case explicitly.","Default to a sentinel (e.g. time.Time{} or the issue's created timestamp) when the field is legitimately empty.","Inspect the raw Jira JSON response to confirm which field is empty and whether that is expected.","If the field should never be empty, check for Jira instance/plugin issues or API version differences."],"exampleFix":"// before\nupdated, err := jira.ParseTimestamp(issue.Fields.Updated)\n// after\nvar updated time.Time\nif issue.Fields.Updated != \"\" {\n    updated, err = jira.ParseTimestamp(issue.Fields.Updated)\n    if err != nil { return err }\n} else {\n    updated, _ = jira.ParseTimestamp(issue.Fields.Created)\n}","handlingStrategy":"validation","validationCode":"func safeParseTimestamp(ts string) (time.Time, error) {\n    if strings.TrimSpace(ts) == \"\" {\n        return time.Time{}, nil // treat unset as zero-value, not an error\n    }\n    return jira.ParseTimestamp(ts)\n}","typeGuard":"func hasTimestamp(s string) bool {\n    return strings.TrimSpace(s) != \"\"\n}","tryCatchPattern":"t, err := jira.ParseTimestamp(ts)\nif err != nil {\n    if strings.Contains(err.Error(), \"empty timestamp\") {\n        t = time.Time{} // or fall back to Created\n    } else {\n        return err\n    }\n}","preventionTips":["Always null/empty-check Jira timestamp fields before parsing.","Prefer omitempty-aware struct unmarshaling so missing fields are detectable.","Default unset 'updated' to 'created' when ordering by recency.","Audit which custom datetime fields can legitimately be empty in your instance."],"tags":["jira","timestamp","parsing","input-validation"],"backgroundTag":"missing-field-value","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}