{"record":{"id":"d87406562a17e2a2","repo":"AdguardTeam/AdGuardHome","slug":"checking-file-q-w","errorCode":null,"errorMessage":"checking file %q: %w","messagePattern":"checking file %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/aghos/fswatcher.go","lineNumber":124,"sourceCode":"func (w *OSWatcher) Shutdown(_ context.Context) (err error) {\n\treturn errors.Annotate(w.watcher.Close(), \"%s: %w\", osWatcherPref)\n}\n\n// Events implements the [FSWatcher] interface for *OSWatcher.\nfunc (w *OSWatcher) Events() (e <-chan Event) {\n\treturn w.events\n}\n\n// Add implements the [FSWatcher] interface for *OSWatcher.  It's safe for\n// concurrent use.\n//\n// TODO(e.burkov):  Make it accept non-existing files to detect it's creating.\nfunc (w *OSWatcher) Add(name string) (err error) {\n\tdefer func() { err = errors.Annotate(err, \"%s: %w\", osWatcherPref) }()\n\n\tfi, err := os.Stat(name)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"checking file %q: %w\", name, err)\n\t}\n\n\t// Watch the directory and filter the events by the file name, since the\n\t// common recomendation to the fsnotify package is to watch the directory\n\t// instead of the file itself.\n\t//\n\t// See https://pkg.go.dev/github.com/fsnotify/fsnotify@v1.7.0#readme-watching-a-file-doesn-t-work-well.\n\tdirName := name\n\tif !fi.IsDir() {\n\t\tdirName = filepath.Dir(name)\n\t}\n\n\tw.filesMu.Lock()\n\tdefer w.filesMu.Unlock()\n\n\tnames := w.files[dirName]\n\tif names == nil {\n\t\tnames = container.NewMapSet[string]()","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/AdguardTeam/AdGuardHome/blob/b41aefbe51c8dde65e2c50f093996afa0502edf9/internal/aghos/fswatcher.go#L106-L142","documentation":"dayRange.validate rejects any schedule range whose start is a negative duration — 'start <val> is negative'. Only the empty range (zero start and end, meaning disabled) is allowed to bypass the checks, so a nonzero negative start always fails.","triggerScenarios":"A weekly schedule day with a negative start value, e.g. \"-01:00\" or a negative millisecond count, during JSON/YAML unmarshalling.","commonSituations":"Timezone conversions producing negative offsets; hand-editing mistakes with minus signs; scripts subtracting durations without clamping at zero.","solutions":["Clamp start to zero or a positive minute-aligned time","Fix the timezone/conversion logic that produced the negative value","Leave the day absent/empty rather than negative to disable it","Re-validate the schedule after correction"],"exampleFix":"// before\n{\"start\": \"-01:00\", \"end\": \"02:00\"}\n// after\n{\"start\": \"01:00\", \"end\": \"02:00\"}","handlingStrategy":"validation","validationCode":"if start < 0 { start = 0 }","typeGuard":"func isNonNegative(d time.Duration) bool { return d >= 0 }","tryCatchPattern":"if err := unmarshalSchedule(data); err != nil && strings.Contains(err.Error(), \"is negative\") {\n    // clamp to zero or omit day, retry\n}","preventionTips":["Clamp computed durations to [0, 24h]","Use absolute times, then convert to durations","Omit days instead of writing negatives"],"tags":["schedule","validation","time","config","go"],"backgroundTag":"config-validation-failed","analyzedSha":"b41aefbe51c8dde65e2c50f093996afa0502edf9","analyzedAt":"2026-08-27T04:57:55.097Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}