instructure/canvas-lms · error · GraphQL::CoercionError

# is not an iso8601 formatted date

Error message

#{time_str.inspect} is not an iso8601 formatted date

What it means

Types::DateTimeType.coerce_input parses incoming date-time strings with Time.zone.iso8601; on ArgumentError it raises GraphQL::CoercionError with "<value> is not an iso8601 formatted date". GraphQL surfaces this as a coercion error on the argument.

Solutions

  1. Send a full ISO8601 timestamp, e.g. 2024-01-15T10:30:00Z
  2. Serialize with date.toISOString() on the client before sending
  3. Validate/normalize the string with a parser before the query
  4. Check for stray empty strings — omit the argument when no date is chosen

Example fix

// before
until: "01/15/2024"
// after
until: new Date("2024-01-15T10:30:00Z").toISOString()
Defensive patterns

Strategy: validation

Validate before calling

function isIso8601(s) { return !isNaN(Date.parse(s)) && /^\d{4}-\d{2}-\d{2}T/.test(s) }
if (!isIso8601(rawDate)) normalizeOrOmit(rawDate)

Type guard

function isValidDateTime(v) { return v == null || (typeof v === 'string' && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(:\d{2})?(\.\d+)?(Z|[+-]\d{2}:?\d{2})?$/.test(v)) }

Try / catch

try { await query(VAR) } catch (e) { if (e.message.includes('is not an iso8601 formatted date')) { refetchWithToISOString() } }

Prevention

When it happens

Trigger: Passing a non-ISO8601 string to any DateTime-typed argument, e.g. "01/15/2024", "2024-01-15" (date only usually ok), "yesterday", or a localized format; also empty strings that reach coercion.

Common situations: UI date pickers emitting locale-formatted dates sent straight to GraphQL; JS Date.toString() output; timezone-less or malformed timestamps; version-dependent strictness of iso8601 parsing.

Related errors


AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15). Data as JSON: /api/errors/d237b15e4ba7cca6. Report an issue: GitHub.

Appendix: source

Thrown at app/graphql/types/date_time_type.rb:32

# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#

class Types::DateTimeType < Types::BaseScalar
  graphql_name "DateTime"
  description "an ISO8601 formatted time string"

  def self.coerce_input(time_str, _)
    if time_str.nil?
      return nil
    end

    Time.zone.iso8601(time_str)
  rescue ArgumentError
    raise GraphQL::CoercionError, "#{time_str.inspect} is not an iso8601 formatted date"
  end

  def self.coerce_result(time, _)
    time.iso8601
  end
end

View on GitHub (pinned to 1c9f0bb801)